![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Ускорение работы с динамическими массивами
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 раза.