J'ai essayé de faire une chose simple qui consiste à former un modèle linéaire avec la Descente de Gradient Stochastique (SGD) à l'aide de la torche:
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])
le code fonctionne très bien et tout bien que mes get_batch2
méthode semble vraiment dum/naïve, c'est probablement parce que je suis nouveau à pytorch mais je n'ai pas trouvé un bon endroit où elles discuter de la façon de récupérer des données des lots. Je suis allé à travers leurs tutoriels (http://pytorch.org/tutorials/beginner/pytorch_with_examples.html) et à travers l'ensemble de données (http://pytorch.org/tutorials/beginner/data_loading_tutorial.html) avec pas de chance. Les tutoriels tous semblent supposer que l'on a déjà du lot et du lot-taille au début et puis continue à s'entraîner avec les données sans les modifier (en particulier à http://pytorch.org/tutorials/beginner/pytorch_with_examples.html#pytorch-variables-and-autograd).
Donc ma question est ai-je vraiment besoin de tourner mes données dans numpy pour que je puisse aller chercher de l'échantillon aléatoire, puis tourner de nouveau à pytorch Variable pour être en mesure de former à la mémoire? Il n'y a pas moyen d'obtenir des mini-lots avec lampe de poche?
J'ai regardé un peu les fonctions de la torche offre, mais avec pas de chance:
#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)
même si le code que j'ai fourni fonctionne très bien, je suis inquiet que ce n'est pas une mise en œuvre efficace ET que si je devais utiliser les Gpu qu'il y aurait beaucoup plus de ralentir (parce que je suppose que c'mettre les choses en mémoire, puis de les chercher en arrière pour les mettre GPU comme ce qui est stupide).
J'ai mis en place un nouveau basé sur la réponse que m'a suggéré d'utiliser 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)
toutefois, cela semble avoir des problèmes car il ne fonctionne pas si X,Y
ne sont PAS des variables...ce qui est vraiment bizarre. J'ai ajouté ceci à la pytorch forum: https://discuss.pytorch.org/t/how-to-get-mini-batches-in-pytorch-in-a-clean-and-efficient-way/10322
Droit maintenant ce que je fais de mal, c'est faire ce travail pour le gpu. Ma version actuelle:
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)
le message d'erreur:
RuntimeError: tried to construct a tensor from a int sequence, but found an item of type numpy.int64 at index (0)
Je ne l'obtenez pas, dois-je vraiment faire:
ints = [ random.randint(0,N) for i i range(M)]
pour obtenir les nombres entiers?
Il serait également idéal si les données pourraient être une variable. Il semble que c' torch.index_select
ne fonctionne pas pour Variable
type de données.
cette liste d'entiers chose ne fonctionne toujours pas:
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)