如何基于输入文本自动生成有意义的选择题?(附Transformer代码)
基于输入文本自动生成选择题的优化方案
问题背景
需要实现基于输入文本自动生成有意义的选择题,无需手动编写题目模板。目前已能通过代码识别关键词的词性(名词、动词、副词、形容词),但仍依赖手动模板生成问题,现基于Transformers框架的T5模型寻求优化方案。
原代码
from transformers import T5ForConditionalGeneration, T5Tokenizer import nltk import random # Load the T5 model and tokenizer model_name = 't5-base' model = T5ForConditionalGeneration.from_pretrained(model_name) tokenizer = T5Tokenizer.from_pretrained(model_name) while True: # Ask the user for input text input_text = input("Enter the input text (or 'exit' to quit): ") if input_text.lower() == 'exit': break # Tokenize the input text words = nltk.word_tokenize(input_text) # Remove stopwords stop_words = set(nltk.corpus.stopwords.words('english')) filtered_words = [word for word in words if word.lower() not in stop_words] # Extract key terms (nouns and proper nouns) key_terms = [word for word, pos in nltk.pos_tag(filtered_words) if pos in ['NN', 'NNS', 'NNP', 'NNPS']] # Shuffle the key terms random.shuffle(key_terms) # Generate 5 multiple-choice questions questions = [] for term in key_terms[:5]: # Limit to 5 key terms options = random.sample(key_terms, 4) options.append(term) random.shuffle(options) correct_answer = options.index(term) # Identify the part of speech pos = nltk.pos_tag([term])[0][1] if pos.startswith('N'): question = f"What is the noun '{term}'?" elif pos.startswith('V'): question = f"How important is the verb '{term}'?" elif pos.startswith('R'): question = f"What is the adverb describing '{term}'?" elif pos.startswith('J'): question = f"What is the adjective describing '{term}'?" else: question = f"What is '{term}'?" questions.append((question, options, correct_answer)) # Print the generated questions for i, (question, options, correct_answer) in enumerate(questions): print(f"Question {i + 1}: {question}") for j, option in enumerate(options): print(f" {chr(65 + j)}. {option}") print(f"Correct Answer: {chr(65 + correct_answer)}\n") # Exiting the loop print("Goodbye!")
优化方案
1. 利用T5模型自动生成语境化问题
替换生硬的手动模板,通过设计针对性prompt让T5结合原文语境生成问题,使题目更贴合文本内容,避免脱离上下文的无效提问。
修改后的问题生成逻辑示例:
def generate_question(model, tokenizer, input_text, term): # 明确任务prompt,引导模型生成符合要求的选择题题干 prompt = f"Generate a clear multiple-choice question asking about the term '{term}' based on this text: {input_text}" inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True) outputs = model.generate(**inputs, max_length=128, num_beams=4, early_stopping=True) return tokenizer.decode(outputs[0], skip_special_tokens=True)
2. 生成语义相关的干扰项
原代码随机选取关键词作为干扰项,易出现选项与问题无关的情况。优化为:
- 针对目标关键词,使用WordNet获取同词性的同义词/近义词作为干扰项
- 若同义词数量不足,补充语义领域相近的词汇,或用原关键词池的其他词汇填充
示例代码(基于WordNet):
from nltk.corpus import wordnet def generate_distractors(term, pos, key_terms, num_distractors=3): distractors = set() # 映射NLTK词性到WordNet词性 pos_map = {'N': wordnet.NOUN, 'V': wordnet.VERB, 'J': wordnet.ADJ, 'R': wordnet.ADV} wordnet_pos = pos_map.get(pos[0], wordnet.NOUN) # 从同义词、上下位词中提取干扰项 for syn in wordnet.synsets(term, pos=wordnet_pos): for lemma in syn.lemmas(): lemma_name = lemma.name().replace('_', ' ') if lemma_name.lower() != term.lower(): distractors.add(lemma_name) for hypernym in syn.hypernyms(): for lemma in hypernym.lemmas(): lemma_name = lemma.name().replace('_', ' ') if lemma_name.lower() != term.lower(): distractors.add(lemma_name) # 取指定数量干扰项,不足则从关键词池补充 distractors = list(distractors)[:num_distractors] if len(distractors) < num_distractors: extra = random.sample([t for t in key_terms if t.lower() != term.lower()], num_distractors - len(distractors)) distractors.extend(extra) return distractors
3. 扩展关键词提取范围并优化精度
原代码仅提取名词,可扩展支持动词、形容词、副词等关键词性;同时用spaCy替代NLTK的基础分词,提升关键词提取的准确性:
import spacy nlp = spacy.load("en_core_web_sm") def extract_key_terms(input_text): doc = nlp(input_text) key_terms = [] # 提取核心词性词汇并过滤停用词 for token in doc: if token.pos_ in ['NOUN', 'PROPN', 'VERB', 'ADJ', 'ADV'] and not token.is_stop: key_terms.append(token.text) # 去重 return list(set(key_terms))
4. 整合优化后的完整代码
将上述优化点整合,替换原代码对应部分,实现自动生成语境化题目和合理干扰项:
from transformers import T5ForConditionalGeneration, T5Tokenizer import nltk import random from nltk.corpus import wordnet import spacy # 加载模型、分词器和NLP工具 model_name = 't5-base' model = T5ForConditionalGeneration.from_pretrained(model_name) tokenizer = T5Tokenizer.from_pretrained(model_name) nlp = spacy.load("en_core_web_sm") nltk.download('wordnet') nltk.download('averaged_perceptron_tagger') def generate_question(model, tokenizer, input_text, term): prompt = f"Generate a clear multiple-choice question asking about the term '{term}' based on this text: {input_text}" inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True) outputs = model.generate(**inputs, max_length=128, num_beams=4, early_stopping=True) return tokenizer.decode(outputs[0], skip_special_tokens=True) def generate_distractors(term, pos, key_terms, num_distractors=3): distractors = set() pos_map = {'N': wordnet.NOUN, 'V': wordnet.VERB, 'J': wordnet.ADJ, 'R': wordnet.ADV} wordnet_pos = pos_map.get(pos[0], wordnet.NOUN) for syn in wordnet.synsets(term, pos=wordnet_pos): for lemma in syn.lemmas(): lemma_name = lemma.name().replace('_', ' ') if lemma_name.lower() != term.lower(): distractors.add(lemma_name) for hypernym in syn.hypernyms(): for lemma in hypernym.lemmas(): lemma_name = lemma.name().replace('_', ' ') if lemma_name.lower() != term.lower(): distractors.add(lemma_name) distractors = list(distractors)[:num_distractors] if len(distractors) < num_distractors: extra = random.sample([t for t in key_terms if t.lower() != term.lower()], num_distractors - len(distractors)) distractors.extend(extra) return distractors def extract_key_terms(input_text): doc = nlp(input_text) key_terms = [] for token in doc: if token.pos_ in ['NOUN', 'PROPN', 'VERB', 'ADJ', 'ADV'] and not token.is_stop: key_terms.append(token.text) return list(set(key_terms)) while True: input_text = input("输入文本(输入'exit'退出):") if input_text.lower() == 'exit': break key_terms = extract_key_terms(input_text) if not key_terms: print("未提取到有效关键词,请输入更丰富的文本。") continue random.shuffle(key_terms) questions = [] for term in key_terms[:5]: pos = nltk.pos_tag([term])[0][1] # 生成问题 question = generate_question(model, tokenizer, input_text, term) # 生成干扰项 distractors = generate_distractors(term, pos, key_terms) options = distractors + [term] random.shuffle(options) correct_answer = options.index(term) questions.append((question, options, correct_answer)) # 输出题目 for i, (question, options, correct_answer) in enumerate(questions): print(f"题目 {i + 1}: {question}") for j, option in enumerate(options): print(f" {chr(65 + j)}. {option}") print(f"正确答案: {chr(65 + correct_answer)}\n") print("再见!")
额外优化建议
- 使用
t5-large等更大的模型可提升问题生成质量,但会增加推理时间 - 可添加过滤逻辑,排除生成的无效问题(如表述模糊、选项重复等)
- 支持批量处理文本,一次性生成多组题目
内容的提问来源于stack exchange,提问作者Pramit
相关产品推荐
相关产品推荐

