原帖把字符串类别列表 truths 转成 NumPy 数组,再传给 torch.from_numpy:
RuntimeError: can't convert a given np.ndarray to a tensor - it has an invalid type. The only supported types are: double, float, int64, int32, and uint8.
先给字符串定义类别语义
np.array(truths) 仍然是字符串数组;换成 NumPy 容器并没有完成分类编码。报错支持类型列表来自旧版,核心约束仍是模型需要数值表示。对类别标签,最重要的是让训练、验证、推理阶段始终使用同一编号表。
普通数值 Tensor 不能直接存储任意字符串。这里不是把数组强行转成某种浮点类型,而是先定义类别到整数的对应关系。
在构造目标之前检查训练标签的实际类型:
import numpy as np
array = np.asarray(truths)
print("josh050608")
print("labels:", array.shape, array.dtype)
print("examples:", truths[:5])
若 truths 是单标签分类的训练字符串列表,可建立并保存映射:
import torch
classes = sorted(set(truths))
class_to_id = {
name: i for i, name in enumerate(classes)}
truth = torch.tensor([class_to_id[name] for name in truths], dtype=torch.long)
验证集和测试集必须复用训练映射,不能各自重新排序编码;模型输出第 i 列的语义也依赖这份映射。保存 checkpoint 时一并保存 classes 或 class_to_id。遇到训练映射中没有的新类别,应显式报错或按任务预先定义未知类,不要临时新增编号超出输出通道。
如果字符串其实是输入文本而非类别标签,应走 tokenizer 生成 token ID、mask 等数值表示;如果是多标签列表,则需要按任务构造多热目标,不能套用上面的单标签编码。
修复后检查 truth.shape == (len(truths),),目标 dtype 为 long,且 truth.max() < 模型类别数。原报错列出的支持类型属于历史版本,现代版本支持类型更多,但仍不意味着可以直接构造字符串 Tensor。
映射复用、未知类别和输出维数一起验证
下面例子从合成训练标签建立映射,验证集复用,并显式拒绝未见过的类别。不会下载或读取数据:
import torch
train_names = ["猫", "狗", "猫", "鸟"]
classes = sorted(set(train_names))
class_to_id = {
name: i for i, name in enumerate(classes)}
def encode(names):
unknown = sorted(set(names) - set(class_to_id))
if unknown:
raise ValueError(f"训练映射中没有这些类别: {unknown}")
return torch.tensor([class_to_id[name] for name in names], dtype=torch.long)
train_target = encode(train_names)
valid_target = encode(["狗", "猫"])
assert [classes[i] for i in train_target.tolist()] == train_names
assert valid_target.max().item() < len(classes)
try:
encode(["鱼"])
except ValueError as exc:
print("unknown class:", exc)
print("mapping:", class_to_id)
如果分别在每个数据划分上 sorted(set(...)),验证集缺少某个类别时编号可能变化,导致同一个数字代表不同类别。映射应和 checkpoint 一起保存,推理展示类名时也用同一份 classes。
原题是类别名称;如果字符串其实是数字读表结果,例如 '1'、'2',先确认它们是类别编号还是连续数值,不要自动按字典序排列后误改数值含义。多标签目标则需要按全部类别构造多热向量,标签 shape 和损失接口也不同。
修复完成后检查类别总数与模型输出列数一致、样本标签能往返解码、未知类别有明确处理。只得到一个 long Tensor 还不够,编号与真实类别的对应关系才决定训练是否正确。