избегание итерации с использованием smart dot / matmul для большого набора данных

#python #numpy

#python #numpy

Вопрос:

Я пытаюсь написать многоклассовый алгоритм персептрона для набора данных MNIST.

теперь у меня есть следующий код, который работает, но из-за того, что он повторяется 60 тысяч раз, он работает медленно.

вес — это размер — (785,10)

 def multiClassPLA(train_data, train_labels, weights):
    epoch_err = []  # will hold the misclassified ratio for each epoch
    best_weights = weights
    best_error = 1

    for epoch in range(EPOCH):
        err = 0
        # randomize the data before each epoch
        train_data, train_labels = randomizeData(train_data, train_labels)
        for x, y in zip(train_data, train_labels):
            h = oneVsAllLabeling_(np.dot(weights, x))
            diff = (y - h) / 2
            x = x.reshape(1, x.shape[0])
            diff = diff.reshape(CLASSES, 1)

            update_step = ETA * np.dot(diff, x)
            weights  = update_step

    return weights
 

Функция oneVsAllLabeling_(X) возвращает вектор, который содержит 1 в argmax и -1 в другом месте. ярлыки истины, конечно, имеют ту же форму.

с помощью этого алгоритма я получаю точность ~ 90%, безопасно, но медленно. после дальнейшего изучения проблемы я обнаружил, что могу улучшить код, используя умножение массива на матрицу.

итак, я начал делать следующее:

 def oneVsAllLabeling(X):
    idx = np.argmax(X, axis=1)
    mask = np.zeros(X.shape, dtype=bool)
    mask[np.arange(len(idx)),idx] = 1
    out = 2 * mask - 1
    return out.astype(int)

def zeroOneError(prediction):
    tester = np.zeros((1, CLASSES))
    good_prediction = len(np.where(prediction == tester))
    return len(prediction) - good_prediction

def preceptronModelFitting(data, weights, labels, to_print, epoch=None):
    prediction = np.matmul(data, weights)
    prediction = oneVsAllLabeling(prediction)
    diff = (prediction - labels) / 2
    error = zeroOneError(diff)
    accuracy = error / len(data)
    if to_print:
        print("Epoch: {}. Loss: {}. Accuracy: {}".format(epoch, error, accuracy))
    return prediction, error, accuracy

def multiClassPLA2(train_data, train_labels, test_data, test_labels, weights):
    predicted_output = np.zeros((1, CLASSES))

    train_loss_vec = np.array([])
    train_accuracy_vec = np.array([])
    test_loss_vec = np.array([])
    test_accuracy_vec = np.array([])

    for epoch in range(EPOCH):
        # randomize the data before each epoch
        train_data, train_labels = randomizeData(train_data, train_labels)
        train_prediction, train_error, train_accuracy = preceptronModelFitting(train_data, weights, train_labels, to_print=False)
    return weights
 

после вызова функции preceptronModelFitting() Я получаю матрицу размером (60k, 10), каждая запись которой имеет следующую форму:

 train_prediction[0]=[0,0,1,0,0,-1,0,0,0,0]
 

и данные имеют форму (60k, 785)

теперь, что мне нужно сделать, это, если возможно, умножить каждую строку на каждую из записей данных и суммировать так, чтобы в итоге я получил матрицу размером (785,10), которую я могу обновить с помощью старого набора весов.

что почти эквивалентно тому, что я делаю в неэффективном алгоритме, единственное отличие заключается в том, что я обновляю веса при каждой новой записи данных, а не после просмотра всех данных.

Спасибо!

Ответ №1:

Хорошо, вы выполнили большую часть работы, и даже у вас была часть ответа в вашем названии.

 np.matmul(X.T, truth - prediction)
 

Используя это, вы получите то, что вы хотите, в одной строке.
обратите внимание, что это основано на том факте, что действительно истина, предсказание, X, как вы упомянули.