Cha*_*ker 32 python numpy machine-learning deep-learning pytorch
我试图做一个简单的事情,用火炬训练带有随机梯度下降(SGD)的线性模型:
import numpy as np
import torch
from torch.autograd import Variable
import pdb
def get_batch2(X,Y,M,dtype):
X,Y = X.data.numpy(), Y.data.numpy()
N = len(Y)
valid_indices = np.array( range(N) )
batch_indices = np.random.choice(valid_indices,size=M,replace=False)
batch_xs = torch.FloatTensor(X[batch_indices,:]).type(dtype)
batch_ys = torch.FloatTensor(Y[batch_indices]).type(dtype)
return Variable(batch_xs, requires_grad=False), Variable(batch_ys, requires_grad=False)
def poly_kernel_matrix( x,D ):
N = len(x)
Kern = np.zeros( (N,D+1) )
for n in range(N):
for d in range(D+1):
Kern[n,d] = x[n]**d;
return Kern
## data params
N=5 # data set size
Degree=4 # number dimensions/features
D_sgd = Degree+1
##
x_true = np.linspace(0,1,N) # the real data points
y = np.sin(2*np.pi*x_true)
y.shape = (N,1)
## TORCH
dtype = torch.FloatTensor
# dtype = torch.cuda.FloatTensor # Uncomment this to run on GPU
X_mdl = poly_kernel_matrix( x_true,Degree )
X_mdl = Variable(torch.FloatTensor(X_mdl).type(dtype), requires_grad=False)
y = Variable(torch.FloatTensor(y).type(dtype), requires_grad=False)
## SGD mdl
w_init = torch.zeros(D_sgd,1).type(dtype)
W = Variable(w_init, requires_grad=True)
M = 5 # mini-batch size
eta = 0.1 # step size
for i in range(500):
batch_xs, batch_ys = get_batch2(X_mdl,y,M,dtype)
# Forward pass: compute predicted y using operations on Variables
y_pred = batch_xs.mm(W)
# Compute and print loss using operations on Variables. Now loss is a Variable of shape (1,) and loss.data is a Tensor of shape (1,); loss.data[0] is a scalar value holding the loss.
loss = (1/N)*(y_pred - batch_ys).pow(2).sum()
# Use autograd to compute the backward pass. Now w will have gradients
loss.backward()
# Update weights using gradient descent; w1.data are Tensors,
# w.grad are Variables and w.grad.data are Tensors.
W.data -= eta * W.grad.data
# Manually zero the gradients after updating weights
W.grad.data.zero_()
#
c_sgd = W.data.numpy()
X_mdl = X_mdl.data.numpy()
y = y.data.numpy()
#
Xc_pinv = np.dot(X_mdl,c_sgd)
print('J(c_sgd) = ', (1/N)*(np.linalg.norm(y-Xc_pinv)**2) )
print('loss = ',loss.data[0])
Run Code Online (Sandbox Code Playgroud)
代码运行正常,虽然我的get_batch2方法看起来真的很简单/天真,但可能是因为我是pytorch的新手,但我还没有找到一个讨论如何检索数据批次的好地方.我通过他们的教程(http://pytorch.org/tutorials/beginner/pytorch_with_examples.html)和数据集(http://pytorch.org/tutorials/beginner/data_loading_tutorial.html)没有运气.这些教程似乎都假设一个人已经在开始时已经拥有批量和批量大小,然后继续使用该数据进行训练而不进行更改(具体请参阅http://pytorch.org/tutorials/beginner/pytorch_with_examples.html# pytorch-variables-and-autograd).
所以我的问题是我是否真的需要将我的数据变回numpy以便我可以获取它的一些随机样本然后将其变回pytorch with Variable以便能够在内存中训练?火炬有没有办法获得迷你批次?
我看了几个功能火炬提供但没有运气:
#pdb.set_trace()
#valid_indices = torch.arange(0,N).numpy()
#valid_indices = np.array( range(N) )
#batch_indices = np.random.choice(valid_indices,size=M,replace=False)
#indices = torch.LongTensor(batch_indices)
#batch_xs, batch_ys = torch.index_select(X_mdl, 0, indices), torch.index_select(y, 0, indices)
#batch_xs,batch_ys = torch.index_select(X_mdl, 0, indices), torch.index_select(y, 0, indices)
Run Code Online (Sandbox Code Playgroud)
即使我提供的代码工作正常,我担心它不是一个有效的实现,如果我使用GPU会有相当大的进一步减速(因为我猜它把东西放在内存中然后把它们拿回来放他们这样的GPU很傻).
我根据建议使用的答案实现了一个新的torch.index_select():
def get_batch2(X,Y,M):
'''
get batch for pytorch model
'''
# TODO fix and make it nicer, there is pytorch forum question
#X,Y = X.data.numpy(), Y.data.numpy()
X,Y = X, Y
N = X.size()[0]
batch_indices = torch.LongTensor( np.random.randint(0,N+1,size=M) )
pdb.set_trace()
batch_xs = torch.index_select(X,0,batch_indices)
batch_ys = torch.index_select(Y,0,batch_indices)
return Variable(batch_xs, requires_grad=False), Variable(batch_ys, requires_grad=False)
Run Code Online (Sandbox Code Playgroud)
然而,这似乎有问题,因为它不起作用,如果X,Y不是变量...这真的很奇怪.我将此添加到pytorch论坛:https://discuss.pytorch.org/t/how-to-get-mini-batches-in-pytorch-in-a-clean-and-efficient-way/10322
现在我正在努力的是让这个工作为gpu.我最新的版本:
def get_batch2(X,Y,M,dtype):
'''
get batch for pytorch model
'''
# TODO fix and make it nicer, there is pytorch forum question
#X,Y = X.data.numpy(), Y.data.numpy()
X,Y = X, Y
N = X.size()[0]
if dtype == torch.cuda.FloatTensor:
batch_indices = torch.cuda.LongTensor( np.random.randint(0,N,size=M) )# without replacement
else:
batch_indices = torch.LongTensor( np.random.randint(0,N,size=M) ).type(dtype) # without replacement
pdb.set_trace()
batch_xs = torch.index_select(X,0,batch_indices)
batch_ys = torch.index_select(Y,0,batch_indices)
return Variable(batch_xs, requires_grad=False), Variable(batch_ys, requires_grad=False)
Run Code Online (Sandbox Code Playgroud)
错误:
RuntimeError: tried to construct a tensor from a int sequence, but found an item of type numpy.int64 at index (0)
Run Code Online (Sandbox Code Playgroud)
我不明白,我真的要这样做:
ints = [ random.randint(0,N) for i i range(M)]
Run Code Online (Sandbox Code Playgroud)
得到整数?
如果数据可以是变量,那也是理想的.它似乎torch.index_select不适用于Variable类型数据.
这个整数列表仍然不起作用:
TypeError: torch.addmm received an invalid combination of arguments - got (int, torch.cuda.FloatTensor, int, torch.cuda.FloatTensor, torch.FloatTensor, out=torch.cuda.FloatTensor), but expected one of:
* (torch.cuda.FloatTensor source, torch.cuda.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
* (torch.cuda.FloatTensor source, torch.cuda.sparse.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
* (float beta, torch.cuda.FloatTensor source, torch.cuda.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
* (torch.cuda.FloatTensor source, float alpha, torch.cuda.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
* (float beta, torch.cuda.FloatTensor source, torch.cuda.sparse.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
* (torch.cuda.FloatTensor source, float alpha, torch.cuda.sparse.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
* (float beta, torch.cuda.FloatTensor source, float alpha, torch.cuda.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
didn't match because some of the arguments have invalid types: (int, torch.cuda.FloatTensor, int, torch.cuda.FloatTensor, torch.FloatTensor, out=torch.cuda.FloatTensor)
* (float beta, torch.cuda.FloatTensor source, float alpha, torch.cuda.sparse.FloatTensor mat1, torch.cuda.FloatTensor mat2, *, torch.cuda.FloatTensor out)
didn't match because some of the arguments have invalid types: (int, torch.cuda.FloatTensor, int, torch.cuda.FloatTensor, torch.FloatTensor, out=torch.cuda.FloatTensor)
Run Code Online (Sandbox Code Playgroud)
Mo *_*sny 28
使用数据加载器.
首先定义数据集.您可以在数据集中torchvision.datasets使用ImageFolder数据集或使用遵循Imagenet结构的数据集类.
trainset=torchvision.datasets.ImageFolder(root='/path/to/your/data/trn', transform=generic_transform)
testset=torchvision.datasets.ImageFolder(root='/path/to/your/data/val', transform=generic_transform)
Run Code Online (Sandbox Code Playgroud)
转换对于动态预处理加载的数据非常有用.如果您使用的是图像,则必须使用ToTensor()变换将加载的图像转换PIL为torch.tensor.可以将更多变换打包到合成变换中,如下所示.
generic_transform = transforms.Compose([
transforms.ToTensor(),
transforms.ToPILImage(),
#transforms.CenterCrop(size=128),
transforms.Lambda(lambda x: myimresize(x, (128, 128))),
transforms.ToTensor(),
transforms.Normalize((0., 0., 0.), (6, 6, 6))
])
Run Code Online (Sandbox Code Playgroud)
然后定义一个数据加载器,在训练时准备下一批.您可以设置数据加载的线程数.
trainloader=torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True, num_workers=8)
testloader=torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False, num_workers=8)
Run Code Online (Sandbox Code Playgroud)
对于培训,您只需枚举数据加载器.
for i, data in enumerate(trainloader, 0):
inputs, labels = data
inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda())
# continue training...
Run Code Online (Sandbox Code Playgroud)
是.您必须转换torch.tensor为numpy使用.numpy()方法来处理它.如果您正在使用CUDA,则必须先使用该.cpu()方法将数据从GPU下载到CPU,然后再进行调用.numpy().就个人而言,来自MATLAB背景,我更喜欢用火炬张量进行大部分工作,然后将数据转换为numpy仅用于可视化.另外请记住,火炬以通道优先模式存储数据,而numpy和PIL使用channel-last.这意味着您需要使用np.rollaxis将通道轴移动到最后一个.示例代码如下.
np.rollaxis(make_grid(mynet.ftrextractor(inputs).data, nrow=8, padding=1).cpu().numpy(), 0, 3)
Run Code Online (Sandbox Code Playgroud)
我发现可视化特征图的最佳方法是使用张量板.yunjey/pytorch-tutorial提供了一个代码.
sae*_*h_g 28
如果我正确理解您的代码,您的get_batch2函数似乎是从数据集中随机进行小批量处理,而不会跟踪您在一个时代中使用过的指数.此实现的问题是它可能不会使用您的所有数据.
我通常进行批处理的方式是使用批量创建所有可能顶点的随机排列,torch.randperm(N)并循环遍历它们.例如:
n_epochs = 100 # or whatever
batch_size = 128 # or whatever
for epoch in range(n_epochs):
# X is a torch Variable
permutation = torch.randperm(X.size()[0])
for i in range(0,X.size()[0], batch_size):
optimizer.zero_grad()
indices = permutation[i:i+batch_size]
batch_x, batch_y = X[indices], Y[indices]
# in case you wanted a semi-full example
outputs = model.forward(batch_x)
loss = lossfunction(outputs,batch_y)
loss.backward()
optimizer.step()
Run Code Online (Sandbox Code Playgroud)
如果您想复制和粘贴,请确保在纪元循环开始之前的某处定义优化器,模型和损失函数.
关于您的错误,请尝试使用torch.from_numpy(np.random.randint(0,N,size=M)).long()而不是torch.LongTensor(np.random.randint(0,N,size=M)).我不确定这是否能解决您所获得的错误,但它将解决未来的错误.
不确定你想要做什么.Wrt批处理你不必转换为numpy.你可以使用index_select(),例如:
for epoch in range(500):
k=0
loss = 0
while k < X_mdl.size(0):
random_batch = [0]*5
for i in range(k,k+M):
random_batch[i] = np.random.choice(N-1)
random_batch = torch.LongTensor(random_batch)
batch_xs = X_mdl.index_select(0, random_batch)
batch_ys = y.index_select(0, random_batch)
# Forward pass: compute predicted y using operations on Variables
y_pred = batch_xs.mul(W)
# etc..
Run Code Online (Sandbox Code Playgroud)
其余的代码也必须改变.
我的猜测,你想创建一个连接你的X张量和Y张量的get_batch函数.就像是:
def make_batch(list_of_tensors):
X, y = list_of_tensors[0]
# may need to unsqueeze X and y to get right dimensions
for i, (sample, label) in enumerate(list_of_tensors[1:]):
X = torch.cat((X, sample), dim=0)
y = torch.cat((y, label), dim=0)
return X, y
Run Code Online (Sandbox Code Playgroud)
然后在训练期间,通过切片选择例如max_batch_size = 32的示例.
for epoch:
X, y = make_batch(list_of_tensors)
X = Variable(X, requires_grad=False)
y = Variable(y, requires_grad=False)
k = 0
while k < X.size(0):
inputs = X[k:k+max_batch_size,:]
labels = y[k:k+max_batch_size,:]
# some computation
k+= max_batch_size
Run Code Online (Sandbox Code Playgroud)
您可以使用 torch.utils.data
假设您已经从目录中加载了数据,在训练和测试 numpy 数组中,您可以从torch.utils.data.Dataset类继承以创建您的数据集对象
class MyDataset(Dataset):
def __init__(self, x, y):
super(MyDataset, self).__init__()
assert x.shape[0] == y.shape[0] # assuming shape[0] = dataset size
self.x = x
self.y = y
def __len__(self):
return self.y.shape[0]
def __getitem__(self, index):
return self.x[index], self.y[index]
Run Code Online (Sandbox Code Playgroud)
然后,创建您的数据集对象
traindata = MyDataset(train_x, train_y)
Run Code Online (Sandbox Code Playgroud)
最后,用于DataLoader创建您的小批量
trainloader = torch.utils.data.DataLoader(traindata, batch_size=64, shuffle=True)
Run Code Online (Sandbox Code Playgroud)