Wie man mini-batches in pytorch in eine saubere und effiziente Art und Weise?

Ich versuche zu tun, eine einfache Sache, die war Zug ein lineares Modell mit Stochastic Gradient Descent (SGD) mit Fackel:

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])

der code läuft einwandfrei und obwohl mein get_batch2 Methode scheint wirklich dum/naiv, seine wahrscheinlich, weil ich bin neu auf pytorch, aber ich habe nicht einen guten Platz gefunden, wo Sie diskutieren, wie Sie Daten abrufen, die Chargen. Ich ging durch Ihren tutorials (http://pytorch.org/tutorials/beginner/pytorch_with_examples.html) und durch die Daten festgelegt (http://pytorch.org/tutorials/beginner/data_loading_tutorial.html) mit kein Glück. Die tutorials scheinen alle davon ausgehen, dass man bereits die batch-und batch-Größe am Anfang und fährt dann mit dem Zug mit, dass Sie Daten, ohne es zu ändern (speziell schauen http://pytorch.org/tutorials/beginner/pytorch_with_examples.html#pytorch-variables-and-autograd).

Also meine Frage ist brauche ich wirklich, um meine Daten wieder in numpy, so dass ich abholen können einige zufällige Stichprobe, und dann schalten Sie es zurück zu pytorch mit Variablen in der Lage sein Zug in Speicher? Gibt es keine Möglichkeit, an mini-batches, die mit der Fackel?

Sah ich ein paar Funktionen Taschenlampe bietet aber mit kein Glück:

#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)

obwohl ich den code zur Verfügung gestellt, funktioniert einwandfrei ich bin besorgt, dass es sich nicht um eine effiziente Umsetzung UND, wenn ich die Verwendung von GPUs, dass es eine weitere erhebliche verlangsamen (weil ich Schätze, Sie setzen Dinge in Erinnerung und dann Holen Sie Sie zurück zu setzen GPU wie das ist albern).


Implementiert habe ich eine neue die auf der Antwort basiert, die vorgeschlagen, dass die Verwendung 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)

jedoch, diese Fragen zu haben scheint, weil es nicht funktioniert, wenn X,Y sind KEINE Variablen...das ist wirklich seltsam. Ich habe dies nur Hinzugefügt, um die pytorch forum: https://discuss.pytorch.org/t/how-to-get-mini-batches-in-pytorch-in-a-clean-and-efficient-way/10322

Jetzt, was ich bin kämpfen, ist mit dieser Arbeit für die gpu. Meine aktuelle version:

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)

den Fehler:

RuntimeError: tried to construct a tensor from a int sequence, but found an item of type numpy.int64 at index (0)

Ich verstehe es nicht, muss ich wirklich zu tun haben:

ints = [ random.randint(0,N) for i i range(M)]

bekommen die ganzen zahlen?

Wäre es auch ideal, wenn die Daten für eine variable. Es scheint, dass es torch.index_select funktioniert nicht für Variable Typ data.

diese Liste von Integer-zahlen, was immer noch nicht funktioniert:

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)
  • auf der pytorch forum: discuss.pytorch.org/t/...
  • nützlich Kommentar vielleicht: Stellen Sie sicher, rufen Sie index_select mit der gleichen Art von Argumenten, d.h. zwei Tensoren oder zwei Variablen. Wickeln Sie Ihre batch_indices in eine Variable oder nutzen Sie einfach X[batch_indices, :].
  • auch im Zusammenhang: discuss.pytorch.org/t/...
Schreibe einen Kommentar