Nano Hash - криптовалюты, майнинг, программирование

работающие с AoA, хранящимися в хэше. PDL против отсутствия PDL

У меня есть хэш AoAs:

$hash{$key} = [ 
               [0.0,1.0,2.0],
               10.0,
               [1.5,9.5,5.5],
              ];

что мне нужно хрустеть следующим образом:

$err += (($hash{$key}[0][$_]-$hash{key}[2][$_])*$hash{$key}[1])**2 foreach (0 .. 2);

вычисление квадрата взвешенной разницы между двумя массивами. Поскольку мой хэш большой, я надеялся, что PDL поможет ускорить вычисления, но по какой-то причине этого не происходит. Я все еще новичок в PDL, поэтому, вероятно, что-то напутал. приведенный ниже скрипт с PDL примерно в 10 раз медленнее. Описание: Следующие два сценария являются моей попыткой просто представить, что происходит в моей программе. Я считываю некоторые эталонные значения в хеш, а затем сравниваю наблюдения (вставленные в хеш на лету) с этими значениями несколько раз с некоторым весом. В сценариях я устанавливаю для эталонного массива, веса и массива наблюдений некоторые произвольные фиксированные значения, но это не будет иметь место во время выполнения.

вот два простых скрипта без PDL и с ним:

без ПДЛ

use strict;
use warnings;
use Time::HiRes qw(time);

my $t1 = time;
my %hash;
my $error = 0;

foreach (0 .. 10000){
  $hash{$_} = [
               [0.000, 1.000, 2.0000],
               10.0,
               [1.5,9.5,5.5],
              ];
  foreach my $i (0 .. 2){
    $error += (($hash{$_}[0][$i]-$hash{$_}[2][$i])*$hash{$_}[1])**2;
  }
}

my $t2 = time;

printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1,$error);

с ПДЛ

use strict;
use warnings;
use PDL;
use Time::HiRes qw(time);

my $t1 = time;
my %hash;
my $error = 0;

foreach (0 .. 10000){
  $hash{$_}[0] = pdl[0.000, 1.000, 2.0000];
  $hash{$_}[1] = pdl[10.0];
  $hash{$_}[2] = pdl[1.5,9.5,5.5];
  my $e = ($hash{$_}[0]-$hash{$_}[2])*$hash{$_}[1];
  $error += inner($e,$e);
}

my $t2 = time;

printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1, $error);
19.06.2011

Ответы:


1

Во-первых, PDL мало чем поможет, если массивы не большие. Таким образом, вместо того, чтобы использовать хэш, проиндексированный от 0 до 10000, каждый из которых (в основном) с семью скалярными элементами, можете ли вы вместо этого создать семь векторов PDL по 10001 элемент каждый и работать с теми, которые используют векторные операции?

Во-вторых, выражение $hash{$_} вычисляется каждый раз, когда вы называете его, поэтому его следует вынести за скобки. Например, в вашем стандартном коде Perl вы должны сделать это:

my $vec = $hash{$_};
foreach my $i (0 .. 2){
    $error += (($vec->[0][$i]-$vec->[2][$i])*$vec->[1])**2;
}
19.06.2011
  • Спасибо, Немо. Я смог добиться скромных успехов с вашими предложениями. Я вставлю скрипт ниже. Факторинг - это то, чем я должен заниматься чаще! 19.06.2011

  • 2

    PDL оптимизирован для работы с массивами. Вы используете хеш для своих данных, но, поскольку ключи являются числами, их можно переформулировать в терминах объектов массива PDL для большого выигрыша в производительности. Следующая полностью PDL-версия примера кода работает примерно в 36 раз быстрее, чем исходный без кода PDLв 300 раз быстрее, чем исходный с кодом PDL).

    все PDL

    use strict;
    use warnings;
    use PDL;
    use Time::HiRes qw(time);
    
    my $t1 = time;
    my %hash;
    my $error = 0;
    
    my $pdl0 = zeros(3,10001);  # create a [3,10001] pdl
    $pdl0 .= pdl[0.000, 1.000, 2.0000];
    
    my $pdl1 = zeros(1,10001);  # create a [1,10001] pdl
    $pdl1 .= pdl[10.0];
    
    my $pdl2 = zeros(3,10001);  # create a [3,10001] pdl
    $pdl2 .= pdl[1.5,9.5,5.5];
    
    my $e = ($pdl0 - $pdl2)*$pdl1;
    $error = sum($e*$e);
    
    my $t2 = time;
    
    printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1, $error);
    

    Подробнее об использовании PDL для вычислений см. в книге по PDL. . домашняя страница PDL также является хорошей отправной точкой для изучения всего, что связано с PDL.

    22.04.2012

    3

    Я рефакторил ваш код несколько раз, сначала вынося как можно больше сложностей за пределы цикла. Во-вторых, я удалил слой или около того абстракции. Это значительно упростило выражение и сократило время выполнения в моей системе примерно на 60%, сохранив при этом тот же результат.

    use Modern::Perl;
    use Time::HiRes qw(time);
    
    my $t1 = time;
    my $error = 0;
    
    my @foo = ( 0.000, 1.000, 2.0000 );
    my $bar = 10.0;
    my @baz = ( 1.5, 9.5, 5.5 );
    
    foreach ( 0 .. 10000 ) {
        $error += ( ( $foo[$_] - $baz[$_] ) * $bar )**2 for 0 .. 2
    }
    
    my $t2 = time;
    
    printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1,$error);
    

    Это просто старый добрый Perl; нет ПДЛ. Надеюсь, это поможет вашему проекту.

    Кстати, при расчете времени, необходимого для выполнения участка кода, я предпочитаю модуль Benchmark с его функциями timethis(), timethese() и cmpthese(). Вы получаете больше информации из него.

    19.06.2011
  • За исключением его фактического приложения, я сомневаюсь, что он работает с 10001 копией одних и тех же данных... Я имею в виду, вы могли бы реорганизовать его код до одной строки (вернуть константу), но, вероятно, он имел в виду не это :-) 19.06.2011
  • спасибо ДавидО. Немо прав. Я отредактирую исходный пост, чтобы сделать его более понятным. 19.06.2011
  • Ага. Я увидел вызов, а затем, приняв его и опубликовав, я увидел свет. ;) Тем не менее, это было веселое упражнение. 19.06.2011
  • Вы вдохновили меня покопаться в Chromatic Modern Perl перед сном! 20.06.2011

  • 4

    Основываясь на предложении Nemo, вот сценарий PDL, который обеспечивает скромный прирост скорости. Я все еще зеленый PDL, так что, вероятно, есть лучший способ. Я также разделил добавление значений в хеш на циклы для ссылок/весов и наблюдений, чтобы сделать OP более похожим на то, что происходит в большей программе, см. «Описание» выше.

    use strict;
    use warnings;
    use PDL;
    use PDL::NiceSlice;
    use Time::HiRes qw(time);
    
    my $t1 = time;
    my %hash;
    my $nvals=10000;
    
    #construct hash of references and weights
    foreach (0 .. $nvals){
      $hash{$_} = [
                     [0.000, 1.000, 2.0000],
                     [10.0, 10.0, 10.0],
                   ];
    }
    
    #record observations
    foreach (0 .. $nvals){
      $hash{$_}[2] = [1.5,9.5,5.5]; 
    }
    
    my $tset = time;
    
    my @ref;
    my @obs;
    my @w;
    
    foreach (0 .. $nvals){
      my $mat = $hash{$_};
      push @ref, @{$mat->[0]};
      push @w,   @{$mat->[1]};
      push @obs, @{$mat->[2]};
    }
    
    my $ref = pdl[@ref];
    my $obs = pdl[@obs];
    my $w   = pdl[@w];
    
    my $diff = (($ref-$obs)*$w)**2;
    my $error = sum($diff);
    
    my $t2 = time;
    
    printf ( "$nvals time setup: %10.4f crunch: %10.4f total: %10.4f error: %10.4f\n", $tset-$t1,$t2-$tset, $t2-$t1,$error);
    
    19.06.2011
  • Я отношу переход от Hash of AoA к pdls к производительности PDL. Чтобы быть справедливым к PDL, мы, вероятно, должны просто сравнить эффективность обычного накопления ошибок perl с pdls {my $diff = (($ref-$obs)*$w)**2; my $error = sum($diff)}, где PDL дает огромный выигрыш в скорости. Поэтому, чтобы сделать это быстрее, мне нужен лучший способ перехода от хэша AoAs к структурам pdl. Я также должен начать использовать модуль Benchmark, предложенный DavidO. 19.06.2011
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..