Болталка PascalABC.NET

Да, но разве в указателях есть знак? Зачем он там?

Причем тут указатели? Забросьте Вы эту дурацкую сишную идеологию. Ну вот как вдолбили человеку когда-то этот С, - все, он обречен. Указатели - смысл всего. Пишите на ассемблере - будут указатели Вам сплошные.

А Вы что имели ввиду? И причём здесь вообще C?

Ну это Ваши проблемы, не так ли?

Мои. Но я ведь не предлагаю их кому-то.

На .Net обойти по производительности C++ - это как?)) Взять хотя бы массивы, которые при каждом доступе к элементу проверяют, не выходит ли индекс за границы. Это оптимизацией не назовёшь. А массивов для нейронной сети надо много… А доступов к их элементам - ещё больше.

С массивами можно работать и по указателям, причём Вы же мне и помогли разобраться, как это сделать. Обойти в прямом смысле слова нельзя, но можно оптимизировать алгоритм под конкретную задачу, а это можно сделать лишь имея все исходники(кроме самых базовых методов). Простой пример: есть динамическая библиотека Math.dll. В ней в классе Stepen объявлен метод НатСтепень(Число: Int32; Степень: Int32), возвращающий Int64. Я думаю, что единственный способ это реализовать следующий:

Library Math;
{$Reference 'System.dll'}
Uses System;
  Type Stepen=Static Class
    Public Static Function НатСтепень(Число: Int32; Степень: Int32): Int64;
    Begin
      Result:=Число;
      For Var i:=0 to Степень-1 do
         Result*=Число;
    End;
  End;
End.

В своей программе Вы подключаете библиотеку и используете вышеописанный метод, ведь это так удобно, метод универсальный, любую степень подписал и всё. Допустим, Вам нужно возвести в 4 степень массив из 100 чисел. Если использовать библиотеку, то получим это:

{$Reference 'Math.dll'}
{$Reference 'System.dll'}
Uses Math;
Uses System;
Procedure ArrMul(arr: array of Single);
Begin
  For Var i:=0 to arr.Length-1 do
    arr[i]:=Stepen.НатСтепень(arr[i], 4);
End;
Begin
  Var a:=new Single[100];
  ArrMul(a);
End.

В принципе, всё хорошо… Или нет? Смотрим: у нас степень, всегда одна и та-же (4), причём совсем небольшая. Зачем использовать цикл для вычисления этой степени(библиотека Math)? Мы ведь с лёгкостью можем написать в программе это:

For Var i:=0 to arr.Length-1 do
Begin
  Var Temp: Single:=arr[i];
  arr[i]*=Temp;
  arr[i]*=Temp;
  arr[i]*=Temp;
End;

Что мы сделали? Очень много. Во-первых, мы “размотали” цикл, убрав таким образом как минимум инкрементацию счётчика и проверку на его соответствие параметру. В конкретно этом примере, это особой погоды не сделает, однако если у нас это место будет повторяться, скажем, 1000000 раз(а такое частенько бывает в нейросетях), то разница будет более чем существенная. Второе: мы отказались от использования метода НатСтепень, и, таким образом, избавились от безусловного перехода(вызова метода), который, являясь одной из команд процессора, требует времени и ресурсов. В итоге, от библиотеки, которая вполне может быть написана на C++ не осталось и следа, а наша программа имеет все шансы превзойти по скорости и потребляемой памяти версию с библиотекой. Это лишь малая часть. Рекомендую почитать следующую статью с Хабра: https://habr.com/post/165729/. Там подробно описаны приёмы оптимизации .NET приложений, кроме того есть результаты тестов, показывающие, что эти ребята переплюнули всех конкурентов, использующих C++. Одним словом - библиотеки предназначены для различных вариантов, то есть их методы или классы сделаны так, чтобы обеспечить максимальную гибкость и простоту при разработке, например, тот-же метод возведения в степень. Он, находясь в библиотеке, достаточно гибок, позволяет возводить в различные степени. Но за гибкость метода (как, в общем-то, и за красивую реализацию), как правило, приходится платить его эффективностью. Ваш пример с массивом правильный. Я пробовал(а теперь и использую) работать с элементами по указателям. Могу сказать только одно: ракообразность указателей с лихвой компенсируется скоростью. Особенно это касается Bitmap’ов(ускорение во много раз).

Во первых, я взял за основу уже готовую “обёртку” из проекта, где есть и dll (толи 1.3 толи 1.4)

Потом доделал её до версии 1.6, так как для неё был рецепт компиляции без ошибок

Ну компилировалась она часа два. Тут можно конфигурировать под конкретный процессор, убрать зависимости от Python … но как выяснилось, всё это не очень нужно - там в ссылке в статье в моём предыдущем комментарии сказано, что можно просто инсталлировать tensorflow под python и переименовать одну из библиотек, которая на самом деле и есть “замаскированная” tensorflow.dll. Там правда есть привязки к python, но в Delphy4Tensorflow они тоже могут использоваться, когда из Pascal ещё и сам Python используется как скриптовый движок.

Если же использовать простую обёртку, с которой я начал, то программы выглядят слишком сложно, вот например перевод Hello TensorFlow:

program TensorFlowHello;

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}
// Pascal with c API implementation of python Hello:
// import tensorflow as tf
// hello = tf.constant('Hello, TensorFlow!')
// sess = tf.Session()
// print(sess.run(hello))

uses tensorflow;
type
  ByteArray = packed array of byte;
  PByteArray = ^ByteArray;
  TFString = packed record
    Aux : size_t;
    Data : shortstring;
  end;
  PTFstring = ^TFString;

var
  graph : pTF_Graph;
  options : pTF_SessionOptions;
  status : pTF_Status;
  session : pTF_Session;
  sHello : PChar = 'Hello, TensorFlow!';
  tensor,tensorOutput : pTF_Tensor;
  operationDescription : pTF_OperationDescription;
  operation : pTF_Operation;
  output : TF_Output;
  P : PTFString;
  SLen,SEncLen : size_t;



begin
  graph := TF_NewGraph;
  options := TF_NewSessionOptions;
  status := TF_NewStatus;
  session := TF_NewSession( graph, options, status );
  SLen := StrLen( sHello );
  SEncLen := TF_StringEncodedSize(SLen);
  tensor := TF_AllocateTensor( TF_STRING, 0, 0, 8 + SEncLen );
  operationDescription := TF_NewOperation( graph, 'Const', 'hello' );

  P :=  TF_TensorData( tensor );
  P^.Aux := 0;
  TF_StringEncode( sHello, SLen, @P^.Data, SEncLen, status );


  TF_SetAttrTensor( operationDescription, 'value', tensor, status );
  TF_SetAttrType( operationDescription, 'dtype', TF_TensorType( tensor ) );
  operation := TF_FinishOperation( operationDescription, status );

  output.oper := operation;
  output.index := 0;

  TF_SessionRun( session, 0,
                 0, 0, 0,  // Inputs
                 @output, @tensorOutput, 1,  // Outputs
                 @operation, 1,  // Operations
                 0, status );
  Writeln('Status code=',TF_GetCode( status ));
  P := TF_TensorData( tensorOutput );
  Writeln(P.Data);
  TF_CloseSession( session, status );
  TF_DeleteSession( session, status );
  TF_DeleteStatus( status );
  TF_DeleteSessionOptions( options );

  readln;
end.


1 лайк

Ну у Паскаля/Delphi уже была одна Алиса (бот)

http://alicebot.sweb.cz/introduction.html

Я имел ввиду Яндекс.Алиса. И безо всяких Uses Яндекс.API.Алиса, а с Uses System. :smile:

А, а я думал Алиса из квантового компьютера в SAO (шутка). Думаете у них в яндексе какие-нибудь нейронные сети используются для генерации ответов, а не та самая Алиса-бот?

Боюсь, это переписывание на Паскаль можно использовать в качестве обучения, а потом придётся использовать всех тех же гигантов. Даже Theano прекратило разработку, так как не захотели соревноваться с TF и прочими.

В качестве простой ML(Mashine Learning) библиотеки можно использовать ConvNetCS. Это библиотека, написана на C# имеет открытый исходный код.

Если знаете её, наверное удобно, а если что-то новое надо изучать, желательно наличие понятной документации

Тут, конечно, дело самого разработчика. Кому-как. Я, например, переписал бы всё на Паскаль и работал бы с полным исходником, но это ИМХО.

А Вы посмотрите на GitHub. Она так и называется, ConvNetCS. Там много примеров, в том числе одной из передовых сетей классификации изображений(VGG16). Код закомментирован и весьма понятен. Я разобрался во всех его тонкостях(и смог переписать его на Паскаль и запустить) примерно за месяц. Вы ведь знаете PascalABC.NET, значит сможете без особых усилий понять и C#. Вполне может быть, что Вам удастся разобраться с ним быстрее, чем мне.

Так в TF есть полный исходник. Но там 1500 контрибуторов и 30000+ коммитов - как собираетесь переписывать такое на Паскаль? Я осознал масштаб проекта, когда он два часа собирался на восьми- ядерном процессоре почти при полной загрузке этих самых ядер и сгенерировал в процессе несколько гигабайт всякого вспомогательного хлама. Тут вопрос, какая часть всего этого нужна. Я посмотрел, вроде ваша программа процентов на 90 состоит из интерфейса и там самого кода сетей всё-таки обозримое количество (неплохо бы кстати разделить всё это на модули).

Так я смотрел. Кстати сравните, один контрибутор - 15 коммитов. Вроде больше информации можно найти в её предшественнике на js. Вроде там достаточно внятно, но похоже, из того что мне надо, чего-то нет. Правда получается, что СonvNetCS это некий способ решить проблемы некой библиотеки на js - то есть опять какая-то деятельность со своей историей, которая в основном адресована тем, кто в ней участвовал, а не более общей аудитории.

Я имел ввиду не переписывать ВСЁ на Паскаль, а только то, что нужно в конкретном проекте. Например, в релизной версии MnistNet нужен слой двумерной свёртки (и только прямой проход через него, как, собственно, и для всех других слоёв), слой линейной ректификации, слой подвыборки(пулинга) и полносвязный слой(с SoftMax). В TF много чего ориентировано на GPU, а это на порядок сложнее, чем CPU(и не всегда удобно в использовании). Кроме того, TF использует кучу сторонних библиотек, пусть и от тех-же разработчиков, следовательно все образовавшиеся зависимости дают такой чудовищный размер файла и время компиляции. P.S. PABCSystem.pas по сравнению с этим монстром-просто игрушка. :slight_smile:

А ведь кто-то(не обязательно именно Вы) говорил мне, что использовать библиотеки лучше, чем писать своими руками с нуля. :smile: А по поводу кода, да, в моих программах, как правило, само тело меньше, чем его графическая оболочка.

Это ещё одна проблема с попытками писать всё самому. Вот разбирал пример с распознаванием фотографий в Caffe - у них там написано с GPU 70ms, без - 1.42s, и это уже много для не очень большой базы фотографий, а у меня, вообще, получилось 20s, может из-за запуска в VirtualBox, но там всё-таки не настолько же тормозит…

А что, в PascalABC.NET нельзя все эти элементы GUI как-нибудь в отдельный модуль вынести? Или вот ещё GraphWPF теперь есть, там же вроде можно конструктор интерфейса использовать. Хотя в последних версиях его нет в виде отдельной программы и он только вместе с самой студией. Знаете, времена когда просто выбора не было и приходилось интерфейс руками писать вызывают не особо приятные воспоминания, чтобы и сейчас этим “развлекаться”, если есть альтернативы.

ОК. Тут полностью с Вами согласен. Мне и самому после MnistNet нехорошо, особенно после объединения интерфейс+тело в один файл. В след. раз буду разделять на интерфейс и тело.

VirtualBox может очень сильно тормозить, поверьте. А применение GPU возможно только в том случае, если ГП поддерживается библиотекой(да и самим компьютером), а такие карты стОят ох как дорого (свыше 20 килорублей). У меня, например, ноут. И мне не очень хотелось бы для запуска нейросети подключать внешнюю видеокарту и разворачивать виртуалку с Linux(которого я вообще не знаю). Я хотел-бы просто жмакнуть на exe-шку, нажать пару кнопочек в красивом окошке с надписями на русском и получить результат(даже если он займёт 20 сек в таком исполнении вместо 1.75 сек с извращениями). Кроме того, на Паскале можно использовать GPU, библиотек для этого завались. И нативные, и с .NET-оболочкой. Так что… У каждого свои интересы и цели. Если Вы собираетесь исследовать архитектуры сетей и обучать их, то да, писать всё на Паскале будет тяжело, а если использовать уже готовые модели, делать их удобными в использовании для простых пользователей, то почему бы и нет. Думаю, спорить по поводу лучшего подхода в реализации сетей никакого смысла, всё равно в этом вопросе не договоримся, так как цели у нас несколько разные.

Так и у меня нет, а встроенный в Intel Video не особо и ускоряет и опять-таки как-то ещё по другому его надо программировать, OpenCL.Так что, из-за этого лишить других людей возможности использовать мою программу c GPU? Так судя по тем цифрам, без GPU серьёзные задачи только отлаживать можно.

А кто об этом спорит? Я вроде как просто пытался обсудить возможность подключения библиотек, так как опыта с PascalABC. NET у меня с этим нет никакого. А Вы говорите надо самому всё писать. Так естественно, если самому всё писать не надо подключать ничего. Но Вы же что-то подключаете. Я даже не пойму что там происходит. Вот эта модель PABCModel она откуда вообще? Тут опять получается, что такой OpenSource на самом деле хорошо замаскированный Closed :slight_smile: То есть где-то наверное как-то обучали, но расчитана программа на то, чтобы ей просто пользовались не залезая особо внутрь.