Задать вопрос

Как оптимизировать код на JS для ускорения работы?

Доброго дня.

Стоит задача рассчитать значения матрицы 52000 на 52000 на JS.
Значение в каждой ячейке является результатом вычисления Косинусовой близости векторов размерностью 300.

Для ускорения вычислений использую GPUJS:

gpu.addFunction(function mF(a, b) {
            return a * b;
        });
const f3 = gpu.createKernel(function(inp) {

            var a = 0
            var b = 0
            var c = 0
            for (var i = 0; i < 300; i++) {
                a += mF(inp[this.thread.y][i], inp[this.thread.x][i])
                b += mF(inp[this.thread.y][i], inp[this.thread.y][i])
                c += mF(inp[this.thread.x][i], inp[this.thread.x][i])
            }

            return a / (Math.pow(b, 0.5) * Math.pow(c, 0.5));

        }).setOutput([52000, 52000])


Можно ли это оптимизировать?

В среднем на расчет всех косинусовых значений от одного вектора ко всем остальным уходит 7мс (без GPU 36 мс), что составляет почти 6 минут для расчета всей матрицы. Я в JS профан и, скорее всего, не вижу очевидных способов оптимизации кода для ускорения его работы.
Так же скрипт благополучно умирает при расчете всей огромной матрицы, приходится считать кусочками по 1000 векторов.

Спасибо
  • Вопрос задан
  • 1589 просмотров
Подписаться 6 Средний 7 комментариев
Решение пользователя Eldrich К ответам на вопрос (4)
@Eldrich Автор вопроса
Нашел решение, объединив возможности библиотеки и совет @Taraflex

Код выглядит так:
var kernelMatrixSize = 4096

        const gpu = new GPU({
            mode: 'gpu'
        });

        const f3 = gpu.createKernel(function(inp1, inp2) {

                var a = 0
                var b = 0
                var c = 0
                for (var i = 0; i < 300; i++) {
                    a += inp1[this.thread.y][i] * inp2[this.thread.x][i]
                    b += Math.pow(inp1[this.thread.y][i], 2)
                    c += Math.pow(inp2[this.thread.x][i], 2)
                }

                return Math.floor(a / (Math.sqrt(b * c)) * 1000000) / 1000000;

            }).setOutput([kernelMatrixSize, kernelMatrixSize])
            .setOutputToTexture(true);
x = getAllDistanceBetween(vectorsData)
y = x[0].toArray(gpu)


Если стоит метка setOutputToTexture, то вычисление матрицы 4096х4096 длится 224 мс, преобразование текстуры в массив занимает примерно 3 секунды. Высчитываем только половину матрицы, так как расстояние от 0 вектора до 1 = расстоянию от 1 к 0. Итого вычисление всех необходимых ячеек займет чуть меньше 60 секунд, вместо 6 минут ранее.

Всем спасибо за помощь.
Ответ написан