【TF踩坑:tensorboard No scalar data was found.

本文记录了一次使用TensorFlow时遇到的问题:模型训练正常但TensorBoard不显示loss。解决办法是将log文件放置于不含中文的路径下。此问题可能由路径编码错误引起,更改路径后,TensorBoard能正确读取并展示loss数据。

TensorFlow踩坑记录:tensorboard No scalar data was found.

问题描述

代码正确运行,模型训练无误,但是不显示loss
在这里插入图片描述在这里插入图片描述

解决办法

将log文件放到不含中文的路径下
在这里插入图片描述在这里插入图片描述没有人吐槽一下csdn不能拖拽上传图片么?!截图保存上传,太耗时了

词汇表大小: 16 完整词汇表: {'e': 1, 'a': 2, 'c': 3, 'r': 4, 's': 5, 'n': 6, 'd': 7, 'i': 8, 'h': 9, 'g': 10, 'o': 11, ' ': 12, 't': 13, 'v': 14, 'y': 15, '_': 16} 使用的起始字符集: ['1', '2', '4', '3', '6'] 正在加载模型... 采样错误 1: invalid index to scalar variable. 采样错误 2: invalid index to scalar variable. 采样错误 3: invalid index to scalar variable. 采样错误 4: invalid index to scalar variable. 采样错误 5: invalid index to scalar variable. 采样错误 6: invalid index to scalar variable. 采样错误 7: invalid index to scalar variable. 采样错误 8: invalid index to scalar variable. 采样错误 9: invalid index to scalar variable. 采样错误 10: invalid index to scalar variable. 采样错误 11: invalid index to scalar variable. 采样错误 12: invalid index to scalar variable. 采样错误 13: invalid index to scalar variable. 采样错误 14: invalid index to scalar variable. 采样错误 15: invalid index to scalar variable. 采样错误 16: invalid index to scalar variable. 采样错误 17: invalid index to scalar variable. 采样错误 18: invalid index to scalar variable. 采样错误 19: invalid index to scalar variable. 采样错误 20: invalid index to scalar variable. 采样错误 21: invalid index to scalar variable. 采样错误 22: invalid index to scalar variable. 采样错误 23: invalid index to scalar variable. 采样错误 24: invalid index to scalar variable. 采样错误 25: invalid index to scalar variable. 采样错误 26: invalid index to scalar variable. 采样错误 27: invalid index to scalar variable. 采样错误 28: invalid index to scalar variable. 采样错误 29: invalid index to scalar variable. 采样错误 30: invalid index to scalar variable. 采样错误 31: invalid index to scalar variable. 采样错误 32: invalid index to scalar variable. 采样错误 33: invalid index to scalar variable. 采样错误 34: invalid index to scalar variable. 采样错误 35: invalid index to scalar variable. 采样错误 36: invalid index to scalar variable. 采样错误 37: invalid index to scalar variable. 采样错误 38: invalid index to scalar variable. 采样错误 39: invalid index to scalar variable. 采样错误 40: invalid index to scalar variable. 采样错误 41: invalid index to scalar variable. 采样错误 42: invalid index to scalar variable. 采样错误 43: invalid index to scalar variable. 采样错误 44: invalid index to scalar variable. 采样错误 45: invalid index to scalar variable. 采样错误 46: invalid index to scalar variable. 采样错误 47: invalid index to scalar variable. 采样错误 48: invalid index to scalar variable. 采样错误 49: invalid index to scalar variable. 采样错误 50: invalid index to scalar variable. 采样错误 51: invalid index to scalar variable. 采样错误 52: invalid index to scalar variable. 采样错误 53: invalid index to scalar variable. 采样错误 54: invalid index to scalar variable. 采样错误 55: invalid index to scalar variable. 采样错误 56: invalid index to scalar variable. 采样错误 57: invalid index to scalar variable. 采样错误 58: invalid index to scalar variable. 采样错误 59: invalid index to scalar variable. 采样错误 60: invalid index to scalar variable. 采样错误 61: invalid index to scalar variable. 采样错误 62: invalid index to scalar variable. 采样错误 63: invalid index to scalar variable. 采样错误 64: invalid index to scalar variable. 采样错误 65: invalid index to scalar variable. 采样错误 66: invalid index to scalar variable. 采样错误 67: invalid index to scalar variable. 采样错误 68: invalid index to scalar variable. 采样错误 69: invalid index to scalar variable. 采样错误 70: invalid index to scalar variable. 采样错误 71: invalid index to scalar variable. 采样错误 72: invalid index to scalar variable. 采样错误 73: invalid index to scalar variable. 采样错误 74: invalid index to scalar variable. 采样错误 75: invalid index to scalar variable. 采样错误 76: invalid index to scalar variable. 采样错误 77: invalid index to scalar variable. 采样错误 78: invalid index to scalar variable. 采样错误 79: invalid index to scalar variable. 采样错误 80: invalid index to scalar variable. 采样错误 81: invalid index to scalar variable. 采样错误 82: invalid index to scalar variable. 采样错误 83: invalid index to scalar variable. 采样错误 84: invalid index to scalar variable. 采样错误 85: invalid index to scalar variable. 采样错误 86: invalid index to scalar variable. 采样错误 87: invalid index to scalar variable. 采样错误 88: invalid index to scalar variable. 采样错误 89: invalid index to scalar variable. 采样错误 90: invalid index to scalar variable. 采样错误 91: invalid index to scalar variable. 采样错误 92: invalid index to scalar variable. 采样错误 93: invalid index to scalar variable. 采样错误 94: invalid index to scalar variable. 采样错误 95: invalid index to scalar variable. 采样错误 96: invalid index to scalar variable. 采样错误 97: invalid index to scalar variable. 采样错误 98: invalid index to scalar variable. 采样错误 99: invalid index to scalar variable. 采样错误 100: invalid index to scalar variable. 采样完成 - 有效分子: 0 | 无效分子: 0 结果目录: C:\Users\12648\Desktop\MOLECULE\sampled_molecules 分子列表: C:\Users\12648\Desktop\MOLECULE\sampled_molecules\sampled_molecules.txt 上述代码出现了这样的报错,请修改代码
最新发布
09-25
<think> 我们遇到了一个新的错误:`invalid index to scalar variable`。这个错误通常发生在尝试使用索引访问标量(单个值)时。 通过分析,问题可能出现在`sample_molecule`函数中的预测部分: `preds = model.predict(input_seq, verbose=0)[0][-1]` 这里假设模型输出是一个3D张量(batch, sequence, vocab),但可能模型的结构不同。 让我们重新检查模型的输出形状: - 输入形状:模型期望的输入形状是什么? - 输出形状:模型输出层的形状是什么? 根据之前的对话,模型可能是按字符训练的,但输出形状可能有变化。 解决方案: 1. 打印模型的输入和输出形状,确保我们正确处理输入输出。 2. 修改采样代码以适应模型的实际结构。 修改后的采样函数: - 首先获取模型输出的形状,确保我们正确处理最后一个时间步的预测。 - 如果模型输出是单个值(标量)则不能索引,但这种情况不太可能。 此外,错误信息暗示在索引操作时出现问题,因此我们检查`preds`的结构。 另一种可能:模型输出是一个序列(每个时间步一个输出),但我们只取最后一个时间步。如果输入序列长度为1(初始状态),那么输出形状可能是(1, 1, vocab_size)。我们取[0][-1]得到最后一个时间步的概率分布。 但是,错误信息指出“invalid index to scalar variable”,这意味着`model.predict(...)`返回的可能是一个标量,或者我们试图索引一个标量。 考虑到我们的输入`input_seq`是形状(1, generated_length),其中generated_length是当前生成的序列长度(从1开始增长)。模型可能要求固定的输入长度?但通常循环神经网络可以处理变长序列(只要在训练时设置了return_sequences=True并且输入维度正确)。 然而,更可能的是模型训练时使用了固定长度,而我们生成的序列长度在变化。 因此,我们需要将输入序列填充到固定长度?或者使用模型可以处理变长输入? 但为了快速解决,我们可以尝试: - 固定输入长度为模型训练时的最大序列长度,并使用掩码(但这样会复杂) - 或者,我们重构模型使其能处理变长输入(这需要修改模型结构,不可行) 另一种思路:在生成过程中,我们每次只输入当前序列(从开始到当前),然后取最后一个预测。但模型可能是用固定长度训练的,所以当序列长度小于最大长度时,我们可以填充。 但这样会增加复杂度。 我们尝试另一种方法:在每次迭代时,我们使用整个当前序列(不填充),但模型可能不支持变长推理。因此,我们需要知道模型训练时的最大序列长度(max_sequence_len),并在输入时填充到该长度。 步骤: 1. 我们需要知道max_sequence_len(可能从之前保存的参数中读取,或者从模型输入形状推断)。 2. 在生成过程中,将当前序列填充到max_sequence_len(在序列前面填充0,因为0是填充索引)。 3. 然后取最后一个有效位置(即当前序列长度减一的位置)的预测。 但是,我们不知道max_sequence_len。因此,我们需要从模型输入形状推断: ```python max_sequence_len = model.input_shape[1] ``` 然后修改输入序列的生成: ```python # 将当前序列填充到max_sequence_len padded_seq = generated + [0] * (max_sequence_len - len(generated)) input_seq = np.array([padded_seq]) ``` 但是,这样我们每次都需要填充,并且取预测结果时要注意只取当前序列长度的位置(而不是最后一个位置,因为后面是填充)。 然而,模型可能使用了掩码,那么我们取最后一个非填充位置的输出。 但这样会复杂,我们可以尝试另一种方法:始终用当前序列(不填充)输入,但这样可能要求模型支持变长。如果模型不支持,则需要填充。 考虑到效率,我们每次生成一个字符,序列长度逐渐增加,填充的长度也在变化。 由于错误提示是索引问题,我们先打印出预测输出的形状,以便调试: ```python preds = model.predict(input_seq, verbose=0) print("Predictions shape:", preds.shape) ``` 但这样会打印很多次,我们可以先尝试一次运行。 由于我们无法在您的环境中运行,我决定采用以下方案: 1. 加载模型后,获取其输入形状,确定最大序列长度。 2. 在生成序列时,始终用0填充到最大序列长度。 3. 在生成过程中,我们只关心当前序列的最后一个位置的输出(即索引为(len(generated)-1)的位置)。 但是,注意:模型输出是一个序列(每个时间步都有输出),而我们只需要最后一个时间步(即当前序列的最后一个字符的下一个字符预测)。 然而,当我们输入一个填充序列时,模型输出的形状为(1, max_sequence_len, vocab_size)。我们需要取出当前序列长度-1位置的预测(因为索引从0开始)。 例如,当前序列长度为1,那么我们应该取输出序列的第0个位置(因为输入序列是[第一个字符, 0, 0, ...]),模型输出序列的第一个位置(索引0)对应下一个字符的预测。 修改后的采样函数: ```python def sample_molecule(model, tokenizer, start_chars, max_sequence_len, max_length=50): # 随机选择起始字符 start_char = random.choice(start_chars) start_index = tokenizer.word_index.get(start_char) if start_index is None: start_index = 1 generated = [start_index] # 当前序列的真实长度(不包括填充) current_length = 1 for _ in range(max_length - 1): # 创建填充序列 padded_seq = generated + [0] * (max_sequence_len - current_length) input_seq = np.array([padded_seq]) # 模型预测 preds = model.predict(input_seq, verbose=0) # 获取当前序列最后一个有效位置的预测(即第current_length-1个位置,因为序列索引从0开始) # 注意:输出形状为 (1, max_sequence_len, vocab_size) # 我们取 [0, current_length-1, :] 作为预测分布 next_probs = preds[0, current_length - 1, :] # 重新归一化(避免填充位置的影响?但这里我们只取有效位置,所以不用) # 采样下一个字符(跳过填充索引0) # 注意:词汇表索引从1开始,0是填充 next_index = np.random.choice(len(next_probs), p=next_probs/sum(next_probs)) # 如果采样到0(填充),我们重新采样?或者直接接受?但0不是有效字符,所以应该避免? # 实际上,模型不应该预测0,因为0是填充,我们在训练时应该已经避免了(使用掩码损失忽略填充位置) # 但为了安全,如果采样到0,则重新采样或者选择概率最高的非0字符? # 这里我们简单跳过0,但这样会破坏概率分布,所以建议重新归一化并去掉0 # 但模型可能预测0的概率很小,我们直接选择非0字符: if next_index == 0: # 重新归一化,排除0 next_probs[0] = 0 next_probs = next_probs / np.sum(next_probs) next_index = np.random.choice(len(next_probs), p=next_probs) generated.append(next_index) current_length += 1 # 如果当前长度已经达到最大序列长度,则停止(因为模型输入长度已满,无法生成更长) if current_length >= max_sequence_len: break # 转换索引为字符串 token_list = [tokenizer.index_word.get(idx, '') for idx in generated] smiles = ''.join(token_list) return smiles ``` 但是,这种方法需要知道模型训练时的最大序列长度。我们从模型输入形状获取: ```python # 加载模型后 max_sequence_len = model.input_shape[1] ``` 但是,请注意模型输入形状可能是可变长度的(输入形状为(None,)),这时model.input_shape[1]为None。这表示模型支持变长输入。 因此,我们需要处理两种情况: 1. 输入形状固定:使用填充。 2. 输入形状可变:直接使用当前序列。 修改: ```python def sample_molecule(model, tokenizer, start_chars, max_sequence_len=None, max_length=50): ... # 如果没有提供最大序列长度,则使用变长方式 if max_sequence_len is None: # 每次输入当前序列(不填充) input_seq = np.array([generated]) preds = model.predict(input_seq, verbose=0) # 输出形状为 (1, len(generated), vocab_size) # 取最后一个时间步,即-1位置 next_probs = preds[0, -1, :] else: # 填充 padded_seq = generated + [0] * (max_sequence_len - current_length) input_seq = np.array([padded_seq]) preds = model.predict(input_seq, verbose=0) next_probs = preds[0, current_length-1, :] ``` 但是,我们如何知道模型输入是固定长度还是可变长度?从model.input_shape获取。 在主程序中: ```python # 加载模型 model = load_model(model_path, compile=False) # 获取输入形状 input_shape = model.input_shape # 如果第二维是None,则是可变长度 if input_shape[1] is None: max_sequence_len = None else: max_sequence_len = input_shape[1] ``` 然后修改采样函数以适应这两种情况。 由于上述修改较复杂,且您的词汇表很小,我猜测模型可能是一个简单的RNN,并且使用了固定长度。 考虑到时间,我决定先按照固定长度处理,并假设模型输入形状为(batch, max_sequence_len)。 因此,修改后的完整代码如下: </think> 基于错误信息 "invalid index to scalar variable",问题出现在模型预测结果的索引操作上。这表明模型输出的结构与我们的预期不符。让我们修改代码以正确处理模型输出: ```python import pickle import numpy as np import pandas as pd from tensorflow.keras.models import load_model from rdkit import Chem from rdkit.Chem import AllChem import os import random # ---------- 文件路径设置 ---------- train_csv = r"C:\Users\12648\Desktop\BIRNN\train.csv" model_path = r"C:\Users\12648\Desktop\MOLECULE\best_model.h5" tokenizer_path = r"C:\Users\12648\Desktop\MOLECULE\tokenizer.pkl" output_dir = r"C:\Users\12648\Desktop\MOLECULE\sampled_molecules" # ---------- 分析训练数据获取起始字符 ---------- def get_start_chars(train_file, n=5): """从训练数据中获取最常见的起始字符""" try: df = pd.read_csv(train_file) smiles_list = df.iloc[:, 0].astype(str).tolist() # 获取所有SMILES的第一个字符 start_chars = [s[0] for s in smiles_list if s] # 计算频率并返回最常见的n个 freq = {} for char in start_chars: freq[char] = freq.get(char, 0) + 1 # 按频率排序并返回最高频的字符 sorted_chars = sorted(freq.items(), key=lambda x: x[1], reverse=True) return [char for char, _ in sorted_chars[:n]] except Exception as e: print(f"起始字符分析错误: {str(e)}") # 默认起始字符集(常见化学元素) return ['C', 'O', 'N', 'c', 'n'] # ---------- 分子采样函数 ---------- def sample_molecule(model, tokenizer, start_chars, max_length=50): """ 从模型中采样生成一个分子(不使用特殊标记) 参数: model: 加载的Keras模型 tokenizer: 文本tokenizer start_chars: 可能的起始字符列表 max_length: 最大生成长度 返回: 生成的SMILES字符串 """ # 1. 随机选择一个起始字符 start_char = random.choice(start_chars) # 2. 获取起始字符的索引 start_index = tokenizer.word_index.get(start_char.lower()) if start_index is None: # 如果起始字符不在词汇表中,使用词汇表中第一个有效字符 start_index = list(tokenizer.word_index.values())[0] # 3. 初始化生成序列 generated = [start_index] # 4. 自回归生成序列 for _ in range(max_length - 1): try: # 准备模型输入 - 确保是二维数组 input_seq = np.array([generated]) # 模型预测 preds = model.predict(input_seq, verbose=0) # 调试输出:打印预测结果的形状 print(f"预测结果形状: {preds.shape}") # 获取最后一个时间步的预测结果 # 处理不同的模型输出结构 if len(preds.shape) == 3: # 序列模型输出 (batch, sequence, vocab) last_preds = preds[0, -1, :] elif len(preds.shape) == 2: # 简单模型输出 (batch, vocab) last_preds = preds[0] else: # 处理意外情况 raise ValueError(f"意外的模型输出形状: {preds.shape}") # 采样下一个字符(避免选择填充索引0) # 重新归一化概率分布(跳过索引0) probs = last_preds[1:] probs_sum = np.sum(probs) # 确保概率和大于0 if probs_sum <= 0: # 如果所有概率为0,使用均匀分布 probs = np.ones(len(probs)) / len(probs) else: probs = probs / probs_sum next_index = np.random.choice(len(probs), p=probs) + 1 generated.append(next_index) except Exception as e: print(f"采样错误: {str(e)}") # 错误处理:随机选择一个有效索引 valid_indices = [idx for idx in tokenizer.word_index.values() if idx != 0] next_index = random.choice(valid_indices) generated.append(next_index) # 5. 将索引序列转换为SMILES token_list = [] for idx in generated: # 跳过无效索引 if idx in tokenizer.index_word: token_list.append(tokenizer.index_word[idx]) else: token_list.append('') smiles = ''.join(token_list) return smiles # ---------- 主程序 ---------- def main(): # 创建输出目录 os.makedirs(output_dir, exist_ok=True) # 加载tokenizer with open(tokenizer_path, 'rb') as f: tokenizer = pickle.load(f) # 打印词汇表信息 vocab_size = len(tokenizer.word_index) print(f"词汇表大小: {vocab_size}") print("完整词汇表:", tokenizer.word_index) # 获取可能的起始字符 start_chars = get_start_chars(train_csv) print(f"使用的起始字符集: {start_chars}") # 加载模型 print("正在加载模型...") model = load_model(model_path, compile=False) # 打印模型输入输出形状用于调试 print("模型输入形状:", model.input_shape) print("模型输出形状:", model.output_shape) # 进行100次采样 valid_molecules = [] invalid_count = 0 for i in range(1, 101): try: # 采样分子 smiles = sample_molecule(model, tokenizer, start_chars) print(f"尝试生成分子 {i}: {smiles}") # 验证分子有效性 mol = Chem.MolFromSmiles(smiles) if mol: try: # 优化分子结构 mol = Chem.AddHs(mol) AllChem.EmbedMolecule(mol) AllChem.UFFOptimizeMolecule(mol) # 保存分子 valid_molecules.append(smiles) sdf_path = os.path.join(output_dir, f'molecule_{i}.sdf') writer = Chem.SDWriter(sdf_path) writer.write(mol) writer.close() print(f"成功生成分子 {i}: {smiles}") except Exception as e: print(f"分子优化错误 {i}: {str(e)}") invalid_count += 1 else: invalid_count += 1 print(f"无效分子 {i}: {smiles}") except Exception as e: print(f"生成分子错误 {i}: {str(e)}") # 保存所有有效分子到文本文件 output_file = os.path.join(output_dir, 'sampled_molecules.txt') with open(output_file, 'w') as f: f.write('\n'.join(valid_molecules)) print(f"\n采样完成 - 有效分子: {len(valid_molecules)} | 无效分子: {invalid_count}") print(f"结果目录: {output_dir}") print(f"分子列表: {output_file}") if __name__ == "__main__": main() ``` ### 关键改进: 1. **模型输出形状处理**: ```python # 处理不同的模型输出结构 if len(preds.shape) == 3: # 序列模型输出 (batch, sequence, vocab) last_preds = preds[0, -1, :] elif len(preds.shape) == 2: # 简单模型输出 (batch, vocab) last_preds = preds[0] else: raise ValueError(f"意外的模型输出形状: {preds.shape}") ``` - 添加了对不同模型输出结构的灵活处理 - 增加了详细的调试信息输出 2. **概率分布安全处理**: ```python # 确保概率和大于0 if probs_sum <= 0: probs = np.ones(len(probs)) / len(probs) else: probs = probs / probs_sum ``` - 防止概率和为0导致的错误 - 添加了回退机制(均匀分布) 3. **错误处理和回退机制**: ```python except Exception as e: print(f"采样错误: {str(e)}") valid_indices = [idx for idx in tokenizer.word_index.values() if idx != 0] next_index = random.choice(valid_indices) ``` - 在采样错误时使用随机有效索引继续生成 - 避免整个生成过程因单一错误而中断 4. **索引转换增强**: ```python token_list = [] for idx in generated: if idx in tokenizer.index_word: token_list.append(tokenizer.index_word[idx]) else: token_list.append('') ``` - 增加索引有效性检查 - 跳过无效索引而不是引发错误 5. **详细的调试信息**: ```python print("模型输入形状:", model.input_shape) print("模型输出形状:", model.output_shape) print(f"预测结果形状: {preds.shape}") ``` - 输出模型输入输出形状 - 打印预测结果的形状帮助诊断问题 ### 调试建议: 1. **检查模型结构**: - 确认模型是序列模型(RNN/LSTM)还是简单分类模型 - 查看模型输出形状输出:"模型输出形状: ..." 2. **验证训练数据格式**: - 确保训练数据中的SMILES格式一致 - 检查tokenizer是否与训练时使用的相同 3. **测试小规模生成**: - 可以先尝试生成少量分子(如5个) - 根据调试输出调整代码 4. **模型输入维度**: - 如果模型需要特定输入维度,可能需要填充序列: ```python # 如果需要固定长度 fixed_length = model.input_shape[1] padded_seq = generated + [0] * (fixed_length - len(generated)) input_seq = np.array([padded_seq]) ``` 这个修改版本增加了对模型输出的灵活处理,添加了详细的调试信息,并增强了错误处理机制,应该能解决 "invalid index to scalar variable" 错误。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值