Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ускорение работы с динамическими массивами


Страницы:   1 2 3 4

alertus ©   (2005-05-24 16:40:00) 

Добрый день, подскажите, пожалуйста, что делать.
Я написал довольно сложный алгоритм (моделирование и обучение нейронных сетей). Все восхитительно работает, но медленно :((

Написал несколько классов для работы с матрицами, нейронными слоями и нейронными сетями, там все построено на динамических массивов real.

Я делаю это так:
var
 a:array of array of real; //матрица
const
 w = 10; //ширина
 h = 5;  //высота
.....
Initialize(a);
SetLength(a,w*h);
i:=2; //столбец
j:=4; //строка
a[j+(i-1)*w]:=0.5; //установим елемент
Finalize(a);


Ну и т.п. все это забито в методы, например
TMatrix.SetElem(i,j:integer;r:real);

Я знаю, что с динамическими массивами можно еще работать так:
type
 myarray = array[1..1000] of real;
 pmyarray = ^myarray;
var
 a:pmyarray;
const
 w = 10;
 h = 5;
.....
i:=2;
j:=4;
getmem(a,w*h*sizeof(real));
a^[j+(i-1)*w]:=0.5;
freemem(a);


Но переписывать все очень долго и не знаю, будет ли выигрыш в скорости.
Может быть вообще надо отказаться от объектно-орентированной концепции, будет не так красиво, но быстро (под вопросом).

Подскажите, пожалуйста, кто сталкивался с подобными вопросами.
Может быть вообще скорость теряется не на динамических массивах, а на многочисленных арифметический операциях, как тогда ускорить их, я уже подумал о
asm
end;


Mx   (2005-05-25 20:34:00) [1]


> alertus ©   (25.05.05 20:31) [76]
> begin...end ©

Пасиб!


begin...end   (2005-05-25 20:32:00) [2]

> alertus ©   (25.05.05 20:31) [76]

Немного медленнее, но не в 3 раза.


alertus   (2005-05-25 20:31:00) [3]

2begin...end
Но ведь все эти операции требуют времени, значит работа с динамическими массивами медленнее.


begin...end   (2005-05-25 20:29:00) [4]

> Mx ©   (25.05.05 20:15) [73]

> Что такое "разыменование"?

Операция получения содержимого памяти по значению указателя.

Что нужно сделать, чтобы получить значение i-го элемента статического массива (будем считать, что он индексируется с нуля), являющегося локальной переменной? Нужно к адресу этой переменной (в стеке) прибавить i * размер_элемента_массивабайт, а затем разыменовать полученный указатель.

А как обстоит дело с локальной переменной динамического массива? Переменная является указателем на область памяти, в которой находятся элементы. Значит, вначале нужно разыменовать адрес переменной в стеке, чтобы получить этот указатель. А потом уже к тому, что получилось, прибавить i * размер_элемента_массивабайт. И после этого -- разыменовать, для получения значения элемента.


alertus   (2005-05-25 20:29:00) [5]

Разыменование указателя - получение значения ячейки памяти, куда он ссылается

a:integer;
b:integer;
p:^integer;
...
a:=5;
p:=@a;
b:=p^;


Последняя операция - разыменование указателя.
Итого: b=5.


Mx   (2005-05-25 20:15:00) [6]


> begin...end ©   (25.05.05 19:33) [65]
> Потому что в случае с дин. массивами требуется двойное
> разыменование.

Что такое "разыменование"? Указатель на указатель?


alertus   (2005-05-25 20:12:00) [7]

Может кто-нибудь поправит, вот часть кода:

unit MatrixCalc;

interface

uses SysUtils,Classes;

const
 SWrongColIndex = 'Индекс столбца %d не соответствует размерности матрицы.';
 SWrongRowIndex = 'Индекс строки %d не соответствует размерности матрицы.';
 SWrongSizesAdd = 'Размеры матриц при сложении не соответсвуют.'+chr(13)+'Ширина и высота первой матрицы должны совпадать с шириной и высотой второй матрицы.';
 SWrongSizesSubtract = 'Размеры матриц при вычитании не соответсвуют.'+chr(13)+'Ширина и высота первой матрицы должны совпадать с шириной и высотой второй матрицы.';
 SWrongSizesMult = 'Размеры матриц при умножении не соответствуют.'+chr(13)+'Ширина первой матрицы должна быть равна высоте второй.';
 SWrongSizesLeftDiv = 'Размеры матриц при левом делении не соответствуют.'+chr(13)+'Высота первой матрицы должна быть равна высоте второй матрицы.';
 SNotSqSizeLeftDiv = 'При левом делении первая матрица должна быть квадратной,'+chr(13)+'Иначе получается недоопределенная или переопределенная система.'+chr(13)+'Такие системы тоже можно решать, но это будет поддерживаться в следующей версии.';
 SWrongStringReadMatrix = 'Неверный формат строки при конвертации строки в матрицу.';
 SWrongHeightsGlue = 'Высоты матриц при горизонтальном склеивании не должны различаться.';
 SWrongWidthsGlue = 'Ширины матриц при вертикальном склеивании не должны различаться.';
 SWrongIndexesFrag = 'При получении фрагмента матрицы заданы неверные индексы:'+chr(13)+'левая верхняя ячейка (%d,%d), правая нижняя ячейка (%d,%d).';

type
 EMatrixError = class(Exception);

 TMatrix = class(TObject)
 private
   w:integer;  //ширина матрицы
   h:integer;  //высота матрицы
   elem:array of array of real;  //массив элементов матрицы
 public
   constructor Create(wset,hset:integer); virtual;
   destructor Destroy; override;
   function GetElem(i,j:integer):real;
   procedure SetElem(i,j:integer;r:real);
   function GetWidth:integer;
   function GetHeight:integer;
 end;

function WriteMatrix(m:TMatrix;escape:boolean):string; //выводит матрицу в строку
function ReadMatrix(s:string;escape:boolean):TMatrix; //читает матрицу из строки
function EyeMatrix(wset,hset:integer;mu:real):TMatrix;  //генерирует матрицу у которой на главной диагонали стоят mu, остальные - нули
function FillMatrix(wset,hset:integer;r:real):TMatrix;  //Заполняет матрицу числом r
function EquateMatrix(m:TMatrix):TMatrix;  //приравнивает матрицы, т.е. создает клон матрицы
function AddNumber(m:TMatrix;r:real):TMatrix;  //прибавляет к каждому элементу матрицы число
function AddMatrix(m1,m2:TMatrix):TMatrix;  //поэлементное сложение матриц
function SubtractMatrix(m1,m2:TMatrix):TMatrix;  //поэлементное вычитание матриц m1-m2
function MultMatrix(m1,m2:TMatrix):TMatrix;  //умножение матриц
function TransMatrix(m:TMatrix):TMatrix;  //транспонирование матрицы
function LeftDivMatrix(m1,m2:TMatrix):TMatrix;  //левое деление матриц, или решение системы линейных уравнений, где первая матрица - коэфициенты левой части, а столбцы второй - правая часть системы, столбцы результата будут решением системы
function GlueMatrix(m1,m2:TMatrix;horiz:boolean):TMatrix;  //Склеивает две матрицы, horiz=true - по горизонтали, horiz=false - по вертикали
function ColMatrix(m:TMatrix;i:integer):TMatrix;  //выводит колонку с номером  n матрицы m в вектор-столбец (матрица-результат)
function FragMatrix(m:TMatrix;i1,j1,i2,j2:integer):TMatrix;  //возвращает матрицу-фрагмент входной матрицы
function SqSumMatrix(m:TMatrix):real;  //возвращает сумму квадратов всех элементов матрицы

implementation

constructor TMatrix.Create(wset,hset:integer);
var
 i,j:integer;
begin
 inherited Create;
 Initialize(elem);
 SetLength(elem,wset,hset);
 w:=wset;
 h:=hset;
 for i:=1 to wset do begin
   for j:=1 to hset do begin
     SetElem(i,j,0);
   end;
 end;
end;

destructor TMatrix.Destroy;
begin
 Finalize(elem);
 inherited Destroy;
end;

function TMatrix.GetElem(i,j:integer):real;
begin
 if (i<1) or (i>w) then begin
   raise EMatrixError.CreateFmt(SWrongColIndex,[i]);
   exit;
 end;
 if (j<1) or (j>h) then begin
   raise EMatrixError.CreateFmt(SWrongRowIndex,[j]);
   exit;
 end;
 result:=elem[i-1,j-1];
end;

procedure TMatrix.SetElem(i,j:integer;r:real);
begin
 if (i<1) or (i>w) then begin
   raise EMatrixError.CreateFmt(SWrongColIndex,[i]);
   exit;
 end;
 if (j<1) or (j>h) then begin
   raise EMatrixError.CreateFmt(SWrongRowIndex,[j]);
   exit;
 end;
 elem[i-1,j-1]:=r;
end;

function TMatrix.GetWidth:integer;
begin
 result:=w;
end;

function TMatrix.GetHeight:integer;
begin
 result:=h;
end;


alertus   (2005-05-25 19:56:00) [8]

Не знаю, я посмотрел модуль NeuralBase, их пишет BaseGroup (там возможностей маловато, но написан он вроде профессионально), я объявления классов у них содрал...
Даже классы исключений написал, хотя они мне не нужны, так, для красоты.
Просто я в объявления классов не силен...
А как лучше сделать??


Kolan   (2005-05-25 19:51:00) [9]


> alertus ©   (25.05.05 19:47) [69]
> 1 слой - плохо, 3 и больше тоже, два - хорошо.
> А еще алгоритмы обучения никуда не годятся, только Левенберг-Марквардт.
> Моя программа может аппроксимировать функции, находит коэффициенты
> рядов Тэйлора и Фурье, распознает образы и многое многое
> другое, но ПРОБЛЕМА!!! циклы обучения медленные, виноват
> не алгоритм, а реализация, в Matlab'бе же все работает точно
> также, но в 5 раз быстрее.


Wowwwwww :)

TMatrix = class (TObject)
private
  w:integer;  //ширина матрицы
  h:integer;  //высота матрицы
  elem:array of array of real;  //массив элементов матрицы
public
  constructor Create(wset,hset:integer); virtual;
  destructor Destroy; override;
  function GetElem(i,j:integer):real;
  procedure SetElem(i,j:integer;r:real);
  function GetWidth:integer;
  function GetHeight:integer;
end;


Мож вот в этом проблема. Зачем делать матрицу наследником TObject?


alertus   (2005-05-25 19:47:00) [10]

1 слой - плохо, 3 и больше тоже, два - хорошо.
А еще алгоритмы обучения никуда не годятся, только Левенберг-Марквардт.
Моя программа может аппроксимировать функции, находит коэффициенты рядов Тэйлора и Фурье, распознает образы и многое многое другое, но ПРОБЛЕМА!!! циклы обучения медленные, виноват не алгоритм, а реализация, в Matlab'бе же все работает точно также, но в 5 раз быстрее.


Kolan   (2005-05-25 19:44:00) [11]

Ну вот я делал 1. Но я схитрил и взял 1 слой. И сё.
Так а ты как сделал?
Я думая тут дело в алгоритме или еще где.


alertus   (2005-05-25 19:37:00) [12]

Я весь алгоритм передрал из Matcad, включая алгоритм Левенберга-Марквардта, самый быстрый алгоритм обучения полносвязных сетей.
А насчет видения сетей, есть как минимум две идеалогии:
1) сеть - массив слоев, слой - массив нейронов, нейрон - массив параметров;
2) сеть - массив слоев, слой - набор матриц параметров (веса, смещения, входы, выходы, всякие вспомогательные).


Kolan   (2005-05-25 19:34:00) [13]

Я что-то наверно упустил. Но вот как я вижу сеть:
Есть класс Нейронн(веса итд).
И есть класс Сеть - массив нейронов. Да?
Потом как ты меняешь веса итд может у тебя алгоритм обратного распространения ошибки неоптимальный? А в maple можно исходник посмотреть? Передири тот алгоритм что там.


begin...end   (2005-05-25 19:33:00) [14]

> Mx ©   (25.05.05 19:30) [63]

Потому что в случае с дин. массивами требуется двойное разыменование.


alertus   (2005-05-25 19:33:00) [15]


> Интересно, а почему в CPU View коды выполнения умножений
> различаются? С дин.массивами на пару инструкций больше.

Факт!


Mx   (2005-05-25 19:30:00) [16]

Интересно, а почему в CPU View коды выполнения умножений различаются? С дин.массивами на пару инструкций больше.


Mx   (2005-05-25 19:28:00) [17]


> begin...end ©   (25.05.05 19:22) [59]
> В данном случае не надо ни Initialize, ни Finalize.

Верно говоришь.


alertus   (2005-05-25 19:26:00) [18]

Кстати, надо выставить цикл побольше, у меня порядка
i:=1 to 1000000000 а в маленьком цикле разницы конечно нет, если счет идет на 1-2 секунды...


alertus   (2005-05-25 19:24:00) [19]

Не знаю, я на двух машинах тестировал, на работе -- в 3 раза, дома -- в 2.
Может от машины зависит??


alertus   (2005-05-25 19:22:00) [20]

Я сравниваю скорость по этому фрагменту:
edit1.text:=timetostr(time);
for i:=1 to 1000000000 do begin
  for j:=0 to 9 do begin
    c[j]:=a[j]*b[j];
  end;
end;
edit2.text:=timetostr(time);

И он отличается минимум в 2 раза.


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо