PyTorch中numpy.ndarray转Tensor失败及AttributeError问题求助
问题
- 环境:numpy 1.25.1、Python 3.10、Torch 2.0.1
- 场景:自定义
EmbeddingDataset类并设置了transform和target_transform,实例化test_data时指定transform=ToTensor(),但直接获取test_data.X得到的仍是numpy.ndarray类型 - 报错情况:
- 调用
X_test.matmul(w)触发:AttributeError: 'numpy.ndarray' object has no attribute 'matmul' - 尝试
X_test.torch.tensor(X).float()触发:AttributeError: 'numpy.ndarray' object has no attribute 'torch'
- 调用
- 疑问:
- 为何
X_test没有被转换为Tensor? - 如何修复这些属性错误?
- 为何
相关代码:
import numpy as np import torch import pickle from torch.utils.data import Dataset from torch.utils.data import DataLoader from torchvision.transforms import ToTensor, Lambda # 自定义Dataset类 class EmbeddingDataset(Dataset): def __init__(self, embedding_fp, transform=None, target_transform=None): with open(embedding_fp, "rb") as fIn: stored_data = pickle.load(fIn) stored_labels = stored_data['labels'] stored_embeddings = stored_data['embeddings'] self.X = stored_embeddings self.y = stored_labels.to_numpy() self.transform = transform self.target_transform = target_transform def __len__(self): return len(self.X) def __getitem__(self, idx): X = self.X[idx] y = self.y[idx] if self.transform: X = self.transform(X) if self.target_transform: y = self.target_transform(y) return X, y # 实例化数据集 train_data = EmbeddingDataset('embeddings_db_train.pkl', transform=ToTensor(), target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))) X_train = train_data.X y_train = train_data.y test_data = EmbeddingDataset('embeddings_db_test.pkl', transform=ToTensor(), target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))) X_test = test_data.X y_test = test_data.y print(type(X_test)) # 输出:numpy.ndarray # 相关函数定义 def plain_accuracy(self, X_test, y_test): # 在原始数据集上评估模型准确率 w = torch.tensor(self.weight) b = torch.tensor(self.bias) out = torch.softmax(X_test.matmul(w) + b).reshape(-1, 1) correct = torch.abs(y_test - out) < 0.5 return correct.float().mean() def softmax(self, enc_x): val_out = enc_x.T.dot(self.weight) + self.bias val_expo = np.array([EncryptedLR.our_exp(x) for x in val_out]) val_pred = np.array([x * EncryptedLR.goldschmidt(x, M=1/EncryptedLR.GOLDSCHMIDT_CONST, n=EncryptedLR.GOLDSCHMIDT_ITER) for x in val_expo]) return val_pred
解答
1. 为何X_test没有被转换为Tensor?
自定义Dataset类中的transform逻辑仅在__getitem__方法中生效——只有当你通过索引(如test_data[0])获取单个样本,或者使用DataLoader批量加载数据时,才会触发transform对数据进行转换。而直接访问test_data.X是读取初始化阶段保存的原始numpy数组,完全没经过transform处理,所以仍是numpy.ndarray类型。
2. 如何修复这些属性错误?
方式一:正确获取经过transform的Tensor数据
如果需要批量的转换后数据,有两种常用方法:
- 方法1:用DataLoader加载
test_loader = DataLoader(test_data, batch_size=len(test_data), shuffle=False) X_test_tensor, y_test_tensor = next(iter(test_loader))
- 方法2:手动遍历Dataset收集
X_test_tensor = [] y_test_tensor = [] for x, y in test_data: X_test_tensor.append(x) y_test_tensor.append(y) X_test_tensor = torch.stack(X_test_tensor) y_test_tensor = torch.stack(y_test_tensor)
方式二:直接转换原始numpy数组
如果不想通过Dataset的__getitem__,可以直接将原始numpy数组转为Tensor:
# 替换原来的X_test = test_data.X X_test_tensor = torch.tensor(test_data.X).float() # 或者复用你设置的ToTensor()转换 X_test_tensor = ToTensor()(test_data.X)
修复具体报错的代码
- 针对
matmul错误:numpy数组没有.matmul()方法,要么用np.matmul(X_test, w)或X_test @ w;如果是Tensor则可以用.matmul()或@。 - 针对错误的Tensor转换:
X_test.torch.tensor(X).float()是语法错误,torch是顶级模块,正确写法是torch.tensor(X_test).float()。
修改后的plain_accuracy函数示例:
def plain_accuracy(self, X_test, y_test): w = torch.tensor(self.weight) b = torch.tensor(self.bias) # 先将X_test转为Tensor(如果传入的还是numpy数组) if isinstance(X_test, np.ndarray): X_test = torch.tensor(X_test).float() # 使用Tensor的matmul或@运算符,注意softmax要指定维度 out = torch.softmax(X_test.matmul(w) + b, dim=1).reshape(-1, 1) # 同时确保y_test也是Tensor类型 if isinstance(y_test, np.ndarray): y_test = torch.tensor(y_test).float() correct = torch.abs(y_test - out) < 0.5 return correct.float().mean()
内容的提问来源于stack exchange,提问作者Bluetail
相关产品推荐
相关产品推荐

