LINUX.ORG.RU

Есть ли смысл использовать для численных расчетов python?

 , ,


6

6

Есть ли смысл использовать для численных расчетов python (методы конечных элементов, математические расчеты, много циклов, большие данные)?

Или лучше использовать c++? Насколько медленнее код получается?

Плюсы питона:

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

Минусы питона:

  • медленнее плюсов
  • после c++ трудно переключится, кое-что по-другому (структуры, switch)
  • я его гораздо хуже знаю

Дал прогу на c++ одному, от так и не смог его осилить :(

Поделитесь историей успеха.

★★★★★
Ответ на: комментарий от grem
$ cat matmultest.cpp 
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
 
using namespace std;
 
const int n=1000;
double a[n][n], b[n][n], bt[n][n], c[n][n];
 
int main()
{
        for (int i=0; i<n; i++)
          for (int j=0; j<n; j++) {
            a[i][j] = (rand() % 100)/100.0+1.0;
            b[i][j] = (rand() % 100)/100.0+1.0;
          }
    
        for (int i=0; i<n; i++)
          for (int j=0; j<n; j++) {
            bt[i][j] = b[j][i];
          }
 
  clock_t start;
  start = clock();
 
        for (int i=0; i<n; i++)
          for (int j=0; j<n; j++) {
            double cc = 0;
            for (int k=0; k<n; k++)
                cc += a[i][k]*bt[j][k];
            c[i][j] = cc;
          }
 
        cout<<(clock()-start)/(double) CLOCKS_PER_SEC<<endl;
        return 0;
}
$ g++ --version
g++ (GCC) 6.3.1 20170109
$ g++ -march=native -Ofast matmultest.cpp
$ ./a.out 
0.349287
$ cat matmultest.py 
import random
import time
import numpy as np

n = 1000

AA = [[random.uniform(0, 1.1) for x in range(n)] for y in range(n)]
BB = [[random.uniform(0, 1.1) for x in range(n)] for y in range(n)]

DD = np.empty([n,n], dtype=np.float64)

start_time = time.time()

DD = np.matmul(AA, BB)

print(" Time %s seconds :" % (time.time() - start_time ))
$ python3 --version
Python 3.6.0
$ python3 matmultest.py 
 Time 2.4748923778533936 seconds :


Я что-то не так сделал или вариант с питоном медленнее в 7 раз?

flyshoot
()
Ответ на: комментарий от crutch_master

Накладные расходы можно получить везде на самом ровном месте

Да. На С сделать намного проще.

fixed

dikiy ★★☆☆☆
()
Ответ на: комментарий от flyshoot

AA = [[random.uniform(0, 1.1) for x in range(n)] for y in range(n)]

Охренеть, код с листами листов всего в 7 раз медленнее.

Сделай AA = numpy.array([[random.uniform(0, 1.1) for x in range(n)] for y in range(n)]), (и для BB), удивишься.

aedeph_ ★★
()
Последнее исправление: aedeph_ (всего исправлений: 1)
Ответ на: комментарий от crutch_master

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

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

dikiy ★★☆☆☆
()
Ответ на: комментарий от flyshoot

А теперь правильный тест:

$ cat matmultest.cpp 
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>

using namespace std;

const int n=4096;
double a[n][n], b[n][n], bt[n][n], c[n][n];

int main()
{
        for (int i=0; i<n; i++)
          for (int j=0; j<n; j++) {
            a[i][j] = (rand() % 100)/100.0+1.0;
            b[i][j] = (rand() % 100)/100.0+1.0;
          }

        for (int i=0; i<n; i++)
          for (int j=0; j<n; j++) {
            bt[i][j] = b[j][i];
          }

  clock_t start;
  start = clock();

        for (int i=0; i<n; i++)
          for (int j=0; j<n; j++) {
            double cc = 0;
            for (int k=0; k<n; k++)
                cc += a[i][k]*bt[j][k];
            c[i][j] = cc;
          }

        cout<<(clock()-start)/(double) CLOCKS_PER_SEC<<endl;
        return 0;
}
$ g++ -march=native -Ofast -o matmultest matmultest.cpp
$ ./matmultest
44.5523
$ time ./matmultest
43.2659

real	0m43.954s
user	0m43.880s
sys	0m0.064s
$ cat matmultest.py
#!/usr/bin/env python
from __future__ import print_function

import numpy as np
import random
import time

n = 4096

AA = [[random.uniform(0, 1.1) for x in range(n)] for y in range(n)]
BB = [[random.uniform(0, 1.1) for x in range(n)] for y in range(n)]

AA = np.array(AA)
BB = np.array(BB)

DD = np.empty([n, n], dtype=np.float)

start_time = time.time()

DD = np.matmul(AA, BB)

print(" Time %s seconds:" % (time.time() - start_time))
$ ./matmultest.py
 Time 6.66353106499 seconds:
$ time ./matmultest.py
 Time 6.64229393005 seconds:

real	0m21.877s
user	0m39.236s
sys	0m1.808s

Итого: на матрицах 4096x4096 питон в 2 раза быстрее (с учетом аллокаций) и в 6 раз быстрее на умножении. Охренеть!

unanimous ★★★★★
()
Последнее исправление: unanimous (всего исправлений: 1)
Ответ на: комментарий от flyshoot

странно, у меня

>python test.py
 Time 0.2670152187347412 seconds :
>python
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32

Сегодня в Mint запускал, питон тоже быстро ответ выдавал, может из-за того, что у меня Core-i3 и размер кэша может влиять, потому как для cpp у меня быстрее секунды не выходит?

>g++ -march=native -Ofast test.cpp
>a
1.097
grem ★★★★★
()
Ответ на: комментарий от unanimous

from __future__ import print_function

кстати, тоже подумал, что это пару десятых секунды сэкономить может :)

dikiy ★★☆☆☆
()
Ответ на: комментарий от aedeph_

Сделай AA = numpy.array([[random.uniform(0, 1.1) for x in range(n)] for y in range(n)]), (и для BB), удивишься.

не, пистон вроде в данном случае сумеет правильно переварить и списки. Но в общем случае array конечно надежней в плане скорости.

dikiy ★★☆☆☆
()
Ответ на: комментарий от aedeph_
$ cat matmultest.py 
import random
import time
import numpy as np

n = 1000

AA = np.array([[random.uniform(0, 1.1) for x in range(n)] for y in range(n)])
BB = np.array([[random.uniform(0, 1.1) for x in range(n)] for y in range(n)])

DD = np.empty([n,n], dtype=np.float64)

start_time = time.time()

DD = np.matmul(AA, BB)

print(" Time %s seconds :" % (time.time() - start_time ))
$ python3 matmultest.py 
 Time 2.4597291946411133 seconds :

Если правильно добавил, то разница невелика.

flyshoot
()
Ответ на: комментарий от dikiy

Он конечно переварит, но если мы сравниваем скорость перемножения, то как-то глупо включать в это ещё время перевода большого листа листов в numpy array.

aedeph_ ★★
()
Ответ на: комментарий от aedeph_

Он конечно переварит, но если мы сравниваем скорость перемножения, то как-то глупо включать в это ещё время перевода большого листа листов в numpy array.

на 1000x1000 разница в 0.1-0.2 секунды.

dikiy ★★☆☆☆
()
Ответ на: комментарий от dikiy

на 1000x1000 разница в 0.1-0.2 секунды.

Что в 10 раз больше, чем время умножения:

Time 0.028722763061523438 seconds : o

aedeph_ ★★
()
Ответ на: комментарий от unanimous

Взял ваш код:

$ ./a.out 
27.798
$ time ./a.out 
27.553

real    0m28,038s
user    0m27,973s
sys     0m0,050s
$ python3 matmultest2.py 
 Time 168.4641785621643 seconds:
$ time python3 matmultest2.py 
 Time 168.12213373184204 seconds:

real    2m58,189s
user    2m57,410s
sys     0m0,310s

flyshoot
()
Ответ на: комментарий от aedeph_
$ python3 num_conf.py
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_info:
  NOT AVAILABLE
atlas_3_10_blas_threads_info:
  NOT AVAILABLE
atlas_3_10_blas_info:
  NOT AVAILABLE
atlas_blas_threads_info:
  NOT AVAILABLE
atlas_blas_info:
  NOT AVAILABLE
blas_info:
    libraries = ['cblas', 'blas']
    library_dirs = ['/usr/lib64']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['cblas', 'blas']
    library_dirs = ['/usr/lib64']
    language = c
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
  NOT AVAILABLE
atlas_3_10_threads_info:
  NOT AVAILABLE
atlas_3_10_info:
  NOT AVAILABLE
atlas_threads_info:
  NOT AVAILABLE
atlas_info:
  NOT AVAILABLE
lapack_info:
    libraries = ['lapack', 'lapack']
    library_dirs = ['/usr/lib64']
    language = f77
lapack_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['lapack', 'lapack', 'cblas', 'blas']
    library_dirs = ['/usr/lib64']
    language = c
None

Хм, видимо чего-то не хватает.

flyshoot
()
Ответ на: комментарий от unanimous

Похоже, что кэш процессора сильно влияет, для n=4096 у меня python3/numpy (15 секунд), cpp/циклы (75 секунд).

grem ★★★★★
()
Ответ на: комментарий от unanimous

А теперь правильный тест

Ага. Велосипед на плюсах «медленнее» специализированной либы на питоне. /0

Ради интереса запустил эти примеры:

% time python3 matmultest.py
 Time 48.9637131690979 seconds:
python3 matmultest.py  63.06s user 0.54s system 99% cpu 1:03.61 total
% time ./matmultest    
49.4487
./matmultest  49.79s user 0.26s system 99% cpu 50.058 total

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Да, то же велосипед на питоне 8 минут считает для N 1000. Если запихнуть вычисление произведения в zip, то раза в 2 быстрее - 3-4 минуты. Поэтому никто в здравом уме такие матрицы не на специализированной либе в питоне считать не будет.

grem ★★★★★
()

Если нужны длинные целые числа, то python предпочтителен, чтобы не связываться с библиотеками. Я стал осторожнее относиться к с для расчётов, после того как натолкнулся на странное поведение: uint64 % uint32 делает нечто неожиданное.

Deleted
()
Ответ на: комментарий от grem

такие матрицы не на специализированной либе в питоне

В питоне нет матриц (без специализированной либы).

aedeph_ ★★
()
Ответ на: комментарий от RazrFalcon

:)

Надо бы научиться в сях подключать и использовать BLAS/LAPACK, для общего развития. В тот велосипед на сях легко openmp втыкается, но на таком мелком N может слишком небольшим прирост быть из-за затрат на раскидывание. Да и обычно интересно не перемножение матриц, а решение слау, разные методы решения которых не всегда хорошо параллелятся: Гаусс, емнип, паралелится с помощью openmp очевиднее чем LU- разложения.

grem ★★★★★
()
Ответ на: комментарий от RazrFalcon

специализированной либы на питоне.

Вообще-то она не на python написана.

anonymous
()
Ответ на: комментарий от anonymous

Я для проверки этого смотрел вывод значений сгенерённых и итоговой матриц и там было 16 знаков после точки. Но хотел бы лучше изучить этот вопрос. Матрицу, в которое запихивал произведение, я инициализировать как float64. Нужно и у исходных попробовать явно задать тип.

grem ★★★★★
()
Ответ на: комментарий от Deleted

Ну так каждый сишник должен знать все UB и прочее. Это же касается и С++.

Тут уж проще использовать Rust, у которого checked arithmetic в дебаге + wrapping из коробки.

RazrFalcon ★★★★★
()
Ответ на: комментарий от flyshoot

То есть питон оказался более чем в 20 раз быстрее.

aedeph_ ★★
()
Ответ на: комментарий от grem

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

Python дал

Time 0.375628948212 seconds 

gcc version 6.3.1 (transposed):

time =  0.945 

gcc version 6.3.1 (naive):

time = 11.417 

clang version 3.8.1 в среднем на десятую долю быстрее в обоих случаях

ZERG ★★★★★
()

слишком много неизвестных, сложно чтото посоветовать... а так, если cuda не планируется использовать, ябы взял python для начала, и по мере выявления медленных кусков переписывал их на cython - для оптимизации циклов и математики он серебряная пуля. а где можно - использовать numpy.
тащемта cuda с цитоном тоже можно подружить, но для этого есть более подходящие инструменты.

genryRar ★★
()
Ответ на: комментарий от RazrFalcon

Для windows:

http://www.netlib.org/blas/#_blas_for_windows (BLAS for windows The reference BLAS is included inside the LAPACK package.)

http://www.openblas.net/ (We provide binary packages for the following platform. Windows x86/x86_64)

это из того, что первое вспомнилось

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 2)
Ответ на: комментарий от RazrFalcon

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

ZERG ★★★★★
()
Ответ на: комментарий от ZERG

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

Из-за того, что это самый популярный сборник бенчей, то всё упирается в странные правила и в желание людей с ними разбираться. То есть самая быстрая прога та, которую лучше всего реализовали. Сам язык не при чём.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Всё равно программисту, имхо, нужно уметь такие вещи самому запихивать в систему (понятия не имею как это делается, я ж не программист). Не всё же может оказаться в дереве пакетов в дистрибутиве.

grem ★★★★★
()
Ответ на: комментарий от aedeph_

Поэтому надо брать atlas для твоей конкретной платформы.

Что С, что пистон пользуются же одной и той же линамической либой.

dikiy ★★☆☆☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.