LINUX.ORG.RU

programming languages performance benchmarks

 , , ,


2

1

А какие еще есть онлайн системы для сравнения производительности реализаций языков программирования кроме всем известного benchmarksgame, который весьма специфичен + там мало языков, а когда-то было намного больше. Фреймворки и открытые библиотеки на основе которых можно сделать нечто подобное тоже приветствуются. Что бы вы хотели видеть в таком сервисе, что можно вообще улучшить?

Ответ на: комментарий от in_dance

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

Так и я об этом. Наверное, стоило сразу это явно обозначить. Я недавно отвечал по поводу реализации встроенной в компилятор арифметики на ARM и прочих RISC — так выяснилось, что в старых версиях GCC были адекватные комментарии и ясные код, а в новых версиях уже и комментов нет, и в коде реализации черт ногу сломит. Где-то в нулевых эта трагедия произошла, до тех пор GCC был вполне себе милашкой.

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

потому в итоге мы имеем вырвиглазный сишный синтаксис повсюду, и бесполезные классы вместо построенных на функциях и типах данных языков.

Да-да, всё началось с того, что разраб C-с-классами неправильно понял концепцию объектов из Smalltalk. И навернули такого идиотизма впоследствии в C++, что пришлось и в ObjectPascal эту моду повторить и углубить. Популяризаторы вроде Буча подыграли на этой теме, а под конец игры посыпали голову пеплом: концепция ООП в том виде, как она реализована на C++ и распространённых ЯП, наоборот усложняла, а не упрощала описание предметной области. Вводились искусственные сущности - паттерны проектирования ради ещё большего абстрагирования от предмета/модели и перехода в совсем уж другую плоскость - программирования самого программирования («фабрики фабрик»).

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

навернули такого идиотизма впоследствии в C++, что пришлось и в ObjectPascal эту моду повторить и углубить

Так эта хрень повторяется, как только новоиспеченное поколение забывает про ошибки предыдущего. Гугл сделал чудовищно переусложненный Angular — принцип построения на компонентах повторил за ним сначала React, потом Vue вместе с Ractive.js/Svelte. В итоге спустя 10 лет автор Svelte взял яйца в руки и сказал «фатит», выкинув компоненты-классы, заменив их простым и чистым JS кодом.

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

Си просто опередил своё время и выстрелил в уже ближе к нулевым. Когда выросло новое поколение, которое массово пришло и в область и в СПО.

Си - это высокоуровневый ассемблер, нужный для переноса наколеночной операционной системы Unics (впоследствии переименованной в «UNIX») - примитивную «односложную» (однопользовательскую) операционную систему на процессоры с другой системой команд. Этот примитив не шёл ни в какое сравнение с тем шедевром инженерной мысли, с которого украли (скорее всего) базовый машинный код на перфоленте и концепцию файловой системы - многозадачной и модульной операционной среды Multics, которая использовала PL/I в качестве системного языка программирования.

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

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

Да: https://www.securityfocus.com/bid/108283

Смотри не засни, листая список список подверженных уязвимости версий ядра.

Можешь и сам поискать:

https://www.cvedetails.com/vulnerability-list/vendor_id-33/product_id-47/cvss...

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

Мне понравилась лекция бабули, которая в 80-х занималась разработкой оптимизирующих компиляторов, и самый запомнившийся мне тезис был плана «это говно невозможно оптимизировать»

https://www.youtube.com/watch?v=Qv-wXcUxrmE - Optimizing Compilers for Parallel Computers, lecture by Frances E. Allen

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

Ну там вроде логическая ошибка, а не оптимизация.

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

Где-то в нулевых эта трагедия произошла, до тех пор GCC был вполне себе милашкой.

И как раз с тех пор его стало возможно использовать для HPC. До этого Intel Fortran его превосходил при работе с массивами раза в два по скорости работы скомпилированной программы.

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

Никакого «Intel Fortran» никогда не существало - шизоид опять врёт.

раза в два по скорости работы скомпилированной программы.

И, конечно же, это трепло никогда пруфвов не предоставит. Хотя если у него какой-то «Intel Fortran» существует, то что с шизоида взять.

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

Но по факту ошибка либо не выдастся, либо выдастся в любом месте, кроме того, где она произошла.

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

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

и даже тогда при падениях адрес ошибки практически всегда верен.

Даже когда адрес верен, сплошь и рядом ситуации типа

   int x = 5;
   g();
   f();
   int y = z / x; // здесь ошибка деления на 0

потому что где-то внутри g или f программист допустил ошибку. При использовании после освобождения ошибка вообще трудновоспроизводима: у клиента падает через раз, в отладчике не падает. Хорошо, хоть valgrind существует.

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

перепутала «зависит от си» и «транслируется в си»?

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

Потому что родить что-то может только мир С/С++

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

Еще каких-то «пацанов» придумал. Нет никаких пацанов, шиз. Есть одни которым интересно смотреть за веселыми шизоидами вроде тебя, а есть легковерные бездарности которым ты впариваешь свою никчемную методичку. А пацанов никаких нет, ты об этом забудь и не говори об этом больше, не позорься.

Просто признай уже что ты аттеншн-вхора, которая постоянно юлит и не отвечает за свои слова.frames

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

И как раз с тех пор его стало возможно использовать для HPC. До этого Intel Fortran его превосходил при работе с массивами раза в два по скорости работы скомпилированной программы.

Откуда инфа? Да, я вижу ускорение, но реальная польза от него весьма сомнительна, и, я подозреваю, что произошло оно благодаря использованию новых векторных инструкций процессора., которые как раз подходят для отдельных операций с массивами:

http://pov4grasp.free.fr/articles/fastpov1/

Вообще, центральный процессор и HPC — это несовместимые вещи так-то, если по по хорошему. Никто не будет на каком-нибудь айфоне майнить битки.

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

Да, я вижу ускорение, но реальная польза от него весьма сомнительна

Другой пользы от использования С и C++ нет. Если скорость некритична, лучше использовать любой язык без UB от OCaml до Java.

И после 2000 в GCC автоматическую векторизацию и агрессивную оптимизацию всего и вся.

Вообще, центральный процессор и HPC — это несовместимые вещи так-то, если по по хорошему. Никто не будет на каком-нибудь айфоне майнить битки.

Не битками едиными… LAPACK перепишешь на CUDA?

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

Собственно, в этом и проблема статических языков

Нет это проблема не статических языков, а языков без развитого метапрограммирования.

В то время как на лиспах почти всё делается на базовом языке и макросах.

В жестко типизированном nemerle все также и делается, там в базе тупо блоки кода и макросы.

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

Вот циклы со счётчиком реально мозг неподготовленному человеку выносят.

Ни разу такого не видел. Но видел людей которые не могли понять рекурсию и не осилили указатели.

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

В школе. Они просто не понимали зачем нужна переменная-счётчик. И трактовали «for(i = 0; i<n; i++)» как заклинание для действия «повторить n раз».

А вот с рекурсией проще. Как получить максимум из n элементов, если уже есть максимум из n-1? Взять первый и сравнить с максимумом из остальных.

Про указатели согласен. Очень неочевидная конструкция.

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

вырвиглазный сишный синтаксис

Да ладно, очень хорош, пока не скатывается в гибрид с лиспом в JS с анонимными функциями

и бесполезные классы вместо построенных на функциях и типах данных

А вот это боль.

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

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

Надо знать историю.

Разработка ЯВУ FORTRAN в 1954-57гг и далее доработки 1978-1995гг были обусловлены необходимостью в научных вычислениях, прежде всего программно-аппаратной реализации векторных вычислений на той аппаратуре, которая была доступна в те времена. Без программных оптимизаций на уровне компилятора не обходилось: распределение элементов матриц по ячейкам памяти с целью минимизации доступа к ним на определённых математических операциях. Грубо говоря, массив байтов распределялся в памяти так, что доступ к элементам столбца проходил быстрее, чем к элементам строк в силу аппаратной особенности. И компилятор учитывал эту особенность регистра ОЗУ при выделении участка памяти под массив.

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

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

Другой пользы от использования С и C++ нет. Если скорость некритична, лучше использовать любой язык без UB от OCaml до Java

Так и используют в итоге. Даже на тех задачах, где скорость критична. Потому что скорость неработающей программы не имеет значения — имеет значение только скорость программы, которая работает. А OCaml и Java позволяют писать работающие программы, в отличие от C/C++.

Не битками едиными… LAPACK перепишешь на CUDA?

Лапак не нужен:

https://docs.nvidia.com/cuda/cusolver/index.html

Даже какая-нибудь бэушная Radeon HD 7970 за 9 тыр на авито имеет производительность по двойной точности где-то как кластер из 8-16 Xeon E-2186G , который обойдется, грубо говоря, в миллион рублей. А происходит этом потому, что ЦП крайне, КРАЙНЕ неэффективно использует транзисторы. Видеокарты имеют примерно 1/10-1/3 производительности идеального специализированного полупроводникового вычислителя (ASIC). В то же время для ЦП это соотношение составляет порядка 1/1000.

То есть, даже школьник с айфоном, в котором есть вычислительная видеокарта, на самом деле располагает большими вычислительными мощностями, чем самый современный сервер на двухпроцессорном Зионе. Именно потому я и пишу, что числодробилки на ЦП не имеют вообще никакого смысла.

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

Потому что скорость неработающей программы не имеет значения — имеет значение только скорость программы, которая работает. А OCaml и Java позволяют писать работающие программы, в отличие от C/C++.

Красиво сказано.

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

А вот с рекурсией проще. Как получить максимум из n элементов, если уже есть максимум из n-1? Взять первый и сравнить с максимумом из остальных

Это проще только до тех пор, пока ты пишешь это русским языком. Проблемы возникают как только это поведение нужно описать четкими логическими конструкциями — кто что кому возвращает, и где же, черт подери, у меня входные параметры, а что будет результатом? Да, рекурсивный алгоритм, как правило, короче, но понять его человеческому моску тяжелее.

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

https://docs.nvidia.com/cuda/cusolver/index.html

И как на нём будет выглядеть

https://numericalalgorithmsgroup.github.io/LAPACK_Examples/examples/doc/dgeqlf_example.html

?

имеет производительность по двойной точности где-то как кластер из 8-16 Xeon E-2186G

Но на весьма ограниченном множестве алгоритмов. FFT вроде есть. А диффуры решать уже проблематично.

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

вырвиглазный сишный синтаксис

Да ладно, очень хорош, пока не скатывается в гибрид с лиспом в JS с анонимными функциями

JS — это язык с большим и тяжелым наследием. Там много проблем было бы с любым синтаксисом. Но! Функция там объявляется как function funcname () {}, а переменная — как let varname = value;. А это уже не сишный синтаксис.

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

Это проще только до тех пор, пока ты пишешь это русским языком.

Если в языке программирования нет лёгкого получения подпоследовательности элементов, то да. На лиспе рекурсивные функции с русского в язык программирования переводятся практически без включения головного мозга. В Си проблема в том, что основная структура – массив/указатель, а из неё подпоследовательность тяжело выковыривать. Хотя обход дерева всё равно проще рекурсивный, чем циклом. А циклы со счётчиком именно русским языком плохо объясняются.

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

Разработка ЯВУ FORTRAN в 1954-57гг и далее доработки 1978-1995гг были обусловлены необходимостью в научных вычислениях, прежде всего программно-аппаратной реализации векторных вычислений на той аппаратуре, которая была доступна в те времена

Прежде всего «доработки 1978-1995гг» были вызваны чудовищно раздутым штатом бездарных «ученых», которые не способны написать сложную программу, освоить боле современный ЯП, и тем более спроектировать микросхему, но могут накидать по шурику что-то работающие на васике или фортране. По иронии судьбы, именно в 1978 запущено производство первых юзабельных микросхем программируемой логики:

https://en.wikipedia.org/wiki/Programmable_Array_Logic

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

Подача корректна, на конкретные детали спорны. Прежде всего проблема переписывания возникает от того, что это некомментированный, недокументированный код с плохой структурированность и плохой модульность. Та же самая история, например, с коболом, потому так тяжело банкам от него уходить. Я за свою короткую жизнь в институте успел потыкать палкой в подобные поделки, и там было вполне нормальным иметь функцию функции с парой десятков аргументов и неговорящими названиями вроде «function raschet1(...)», «function raschet2(...)».

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

Это сишный синтаксис, дошколёнок. Всё, () {}, fun(). {} для объектов. Это всё си.

К тому же откуда ты высрала let, если его никогда там не было, позорище.

Паскалятское var, как и function - не имеет никакого отношения к синтаксису. Это просто примитивное дерьмо. Опорные кейворды использует любая бездарная скриптуха, потому как разбирать такую грамматику на порядок проще.

Поэтому в си было fun() {} - это говно распарсить неможет, добавлен был опорный кейворд.

В паскалятине признаком декларации всегда являлася оператор пиписька. = - это сишка. Как и признак декларации через кейворд/квалификаторы, а уже далее тип.

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

И как на нём будет выглядеть
https://numericalalgorithmsgroup.github.io/LAPACK_Examples/examples/doc/dgeql...

ХЗ, я не нахожу там QL факторизации, cusolver через QR факторизацию предлагает считать наименьшие квадраты.

Но на весьма ограниченном множестве алгоритмов. FFT вроде есть. А диффуры решать уже проблематично

Смотря какие. Достаточно простые можно распараллелить на мелкие независимые операции.

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

В паскалятине признаком декларации всегда является оператор ПИСЮН - это сишка. Как и признак декларации через кейворд/квалификаторы - это СИСЬКИ.

Царь?

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

Распараллелить можно. Операции в CUDA есть не все (по сравнению с ЦП). И я не уверен, что тех что есть для диффуров хватит. А если после каждой операции вытаскивать обратно на ЦП, чтобы выбрать ветвь алгоритма, то на ЦП посчитать быстрее будет. Или всё на одно ядро GPU кидать, что тоже малоосмысленно.

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

Что хотел бы видеть я в первую очередь - это сравнение идиоматического кода на разных языках

Что мешает вам написать идиоматический код и запустить измерения на своей машине, зачем для этого «онлайн системы»?

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

Распараллелить можно. Операции в CUDA есть не все (по сравнению с ЦП). И я не уверен, что тех что есть для диффуров хватит

https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#arithmetic-i...

Коротко: очень быстро работает сложение, умножение, и сложение с умножением, где-то в четыре раза медленнее работает вычитание, вычисление обратного числа, логарифма по двойке и степени двойки, синус-косинус. Да, с этими операциями видюха будет быстрее не в 100 раз, а только в 20 — это все равно овердофига.

А если после каждой операции вытаскивать обратно на ЦП, чтобы выбрать ветвь алгоритма, то на ЦП посчитать быстрее будет

У GPGPU есть инструкции уровня какого-нибудь RISC процессора. Ограничение там только в отсутствии стэка вызовов (или серьезной ограниченности) — что свойственно и другим RISC-процессорам. Ну и код на лету не сгенерируешь, и указатель на функцию не передашь, и рекурсивно функцию не вызовешь. Как раз фортрановые программы на такой процессор прекрасно налазят, но скорость выполнения у инструкций вроде «взять одно число, проверить его значение, сделать условный переход» очень низкая.

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

Удобно, когда есть куча языков и платформ, многие из них у меня не будут стоять в системе, на других я не знаю, как там надо писать «правильно».

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

Коротко: очень быстро работает сложение, умножение, и сложение с умножением

Только если их можно кидать пакетами по 256 штук. А если для каждой следующей операции нужен результат предыдущей? Тогда на ЦП тактовая частота в несколько раз выше и есть конвейер.

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

Ну и код на лету не сгенерируешь, и указатель на функцию не передашь, и рекурсивно функцию не вызовешь.

Судя по PTX CUDA, есть call/ret и в call можно передать указатель. Но вот скорость работы на одном ядре (если не параллелится), не впечатляет.

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

Судя по PTX CUDA, есть call/ret и в call можно передать указатель

«The local state space (.local) is private memory for each thread to keep its own data. It is typically standard memory with cache. The size is limited, as it must be allocated on a per-thread basis. Use ld.local and st.local to access local variables.

When compiling to use the Application Binary Interface (ABI), .local state-space variables must be declared within function scope and are allocated on the stack. In implementations that do not support a stack, all local memory variables are stored at fixed addresses, recursive function calls are not supported, and .local variables may be declared at module scope. When compiling legacy PTX code (ISA versions prior to 3.0) containing module-scoped .local variables, the compiler silently disables use of the ABI.»

Ну и дальше секция https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#control-flo...

Поскольку поток выполнения в GPGPU — это, на самом деле, несколько поток вычисления, то непрямой вызов функции с потенциальным расхождением путей выполнения на самом деле является созданием новых потоков выполнения (и их контекстов). Может это и дешевле, чем pthread_create в мире ЦП, но дороже, чем ожидается от простого вызова функции..

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

Только если их можно кидать пакетами по 256 штук. А если для каждой следующей операции нужен результат предыдущей? Тогда на ЦП тактовая частота в несколько раз выше и есть конвейер

Таких задач, на самом деле, не так много. Это в 8080, который обрабатывает по одному символу за такт и в принципе не может ничего быстрее делать, по-другому ты алгоритмы не напишешь. А сейчас даже для чтения текстового файла с разбором на строки или просто какие-то токены можно использовать параллельные алгоритмы, которые анализируют по таблицам сразу двести символов за такт, эта таблица оказывается в едином кэше у всех потоков, а потому выполнять предварительный парсинг можно нереально быстро, несравнимо быстрее посимвольного чтения на ЦП. Конечно, при этом языки вроде C++, у которых контекстно-зависимый синтаксис, который значительно усложняет задачу.

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

массив байтов распределялся в памяти так, что доступ к элементам столбца проходил быстрее, чем к элементам строк в силу аппаратной особенности. И компилятор учитывал эту особенность регистра ОЗУ при выделении участка памяти под массив.

Это просто традиция от ранних реализаций: A(1), A(2), A(3) – то же самое, что и A(1,1), A(2,1), A(3,1)

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

Turbo Pascal, который в свое время давал пососать и сишным компиляторам

Забыл добавить, твоему сишному канпелятору. А так смешно, да.

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

Красиво сказано

Тебя тоже окружают «работающие» программы на окамле и «неработающие» на си? Бывает, чо.

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

Turbo Pascal, который в свое время давал пососать и сишным компиляторам

Забыл добавить, твоему сишному канпелятору.

Может быть, этому компилятору «С» ?

https://www.drdobbs.com/developer-network-small-c-compiler-book/184415519

http://twimgs.com/ddj/sdmediagroup/images/sdm1123195158574/ddj_devnetwork_small_c.zip

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

Забыл добавить, твоему сишному канпелятору. А так смешно, да

Во время 286 процессора c миллионом целочисленных операций в секунду оптимизирующие компиляторы были маловостребованы, потому что никто не хотел сидеть ждать две минуты, пока соптимизируются пять тысяч строк на Си. Это сейчас твой GCC потратит полсекунды на компиляцию аналогичного проекта, а теперь умнож это цифру на десять тысяч — примерно такое отношение производительности 286 и более-менее современного пенька. Потому оптимизации, если нужно, писали на асме. Тем более, что асм в те времена был попроще, потому что и процессоры были попроще.

Ирония судьбы, но компиляция кода на C/C++ по прежнему очень медленная.

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

Тебя тоже окружают «работающие» программы на окамле и «неработающие» на си? Бывает, чо

«Работающие программы» на Си, которые ты как бы подразумеваешь — это, на самом деле, единичные софтины, которые разрабатываются и тестируются большой толпой. И в этих единичных софтинах, по-хорошему, можно было бы написать узкие места на асме под каждую архитектуру. Ну, что значит «можно было бы» — их таки пишут на асме под каждую платформу, но иногда хватает оптимизаций сишного компилятора. То же ядро линя содержит примерно 1.5% кода на асме.

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

Никакого «Intel Fortran» никогда не существало - шизоид опять врёт.

Он совершенно прав до того момента пока griggorii не нагенерировал новых ллвэмов да гегеце и не разбросал по гитхабам да в раздавайке маздайке

anonymous
()
Ответ на: комментарий от byko3y
Какой Адам на ваш вкус более энергетически эффективен, Turbato corde?
template <typename T, class Context>
class AdamOp final : public Operator<Context> {
 public:
  USE_OPERATOR_CONTEXT_FUNCTIONS;
  AdamOp(const OperatorDef& operator_def, Workspace* ws)
      : Operator<Context>(operator_def, ws),
        beta1_(this->template GetSingleArgument<float>("beta1", 0.9f)),
        beta2_(this->template GetSingleArgument<float>("beta2", 0.999f)),
        epsilon_(this->template GetSingleArgument<float>("epsilon", 1e-5f)) {}
  bool RunOnDevice() override {

    const auto iter =
        OperatorBase::Input<Tensor>(ITER, CPU).template data<int64_t>()[0];

    const auto t = iter + 1;
    const auto correction =
        std::sqrt(T(1.) - std::pow(beta2_, t)) / (T(1.) - std::pow(beta1_, t));
    if (OutputSize() == 3) {
      adam_compute<Context>(
          Input(GRAD).numel(),
          Input(PARAM).template data<T>(),
          Input(GRAD).template data<T>(),
          Input(MOMENT_1).template data<T>(),
          Input(MOMENT_2).template data<T>(),
          Output(OUTPUT_PARAM)->template mutable_data<T>(),
          Output(OUTPUT_MOMENT_1)->template mutable_data<T>(),
          Output(OUTPUT_MOMENT_2)->template mutable_data<T>(),
          beta1_,
          beta2_,
          epsilon_,
          correction,
          Input(LR).template data<T>(),
          &context_);
    } else {
      Output(OUTPUT_GRAD)->ResizeLike(Input(GRAD));
      adam_compute_output_grad<Context>(
          Input(GRAD).numel(),
          Input(PARAM).template data<T>(),
          Input(GRAD).template data<T>(),
          Input(MOMENT_1).template data<T>(),
          Input(MOMENT_2).template data<T>(),
          Output(OUTPUT_PARAM)->template mutable_data<T>(),
          Output(OUTPUT_MOMENT_1)->template mutable_data<T>(),
          Output(OUTPUT_MOMENT_2)->template mutable_data<T>(),
          Output(OUTPUT_GRAD)->template mutable_data<T>(),
          beta1_,
          beta2_,
          epsilon_,
          correction,
          Input(LR).template data<T>(),
          &context_);
    }

    return true;
  }

 protected:
  T beta1_{0.9};
  T beta2_{0.999};
  T epsilon_{1e-8};
  INPUT_TAGS(PARAM, MOMENT_1, MOMENT_2, GRAD, LR, ITER);
  OUTPUT_TAGS(OUTPUT_PARAM, OUTPUT_MOMENT_1, OUTPUT_MOMENT_2, OUTPUT_GRAD);
};
template <typename T>
struct ApplyAdamWithAmsgrad<GPUDevice, T> {
  void operator()(const GPUDevice& d, typename TTypes<T>::Flat var,
                  typename TTypes<T>::Flat m, typename TTypes<T>::Flat v,
                  typename TTypes<T>::Flat vhat,
                  typename TTypes<T>::ConstScalar beta1_power,
                  typename TTypes<T>::ConstScalar beta2_power,
                  typename TTypes<T>::ConstScalar lr,
                  typename TTypes<T>::ConstScalar beta1,
                  typename TTypes<T>::ConstScalar beta2,
                  typename TTypes<T>::ConstScalar epsilon,
                  typename TTypes<T>::ConstFlat grad) {
    Eigen::array<typename TTypes<T>::Tensor::Index, 1> bcast;
    bcast[0] = grad.dimension(0);
    Eigen::Sizes<1> single;
    const auto one = static_cast<T>(1.0);
    m.device(d) =
        m + (beta1.constant(one) - beta1).reshape(single).broadcast(bcast) *
                (grad - m);
    v.device(d) =
        v + (beta2.constant(one) - beta2).reshape(single).broadcast(bcast) *
                (grad.square() - v);
    vhat.device(d) = vhat.cwiseMax(v);

    var.device(d) -= (lr * (beta2_power.constant(one) - beta2_power).sqrt() /
                      (beta1_power.constant(one) - beta1_power))
                         .reshape(single)
                         .broadcast(bcast) *
                     m /
                     (epsilon.reshape(single).broadcast(bcast) + vhat.sqrt());
  }
};
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.