Pull to refresh
8K+
18
9
Rating
3
Subscribers
Send message

loss_output нужен только для отрисовки графика функции потерь. Согласен, что в ранее предложенной реализации есть неоднозначность со значением loss_output. Поправил код в статье.

   def learn(self) -> float:
        memory_sample_tuples = self.memory.load_sample_random_positive()
        loss_output = 0
        if len(memory_sample_tuples) > 0:
            loss_output = self.policy_explotate.learn(memory_sample_tuples)      

        return loss_output

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

В финальном примере у меня этот случай обрабатывается, а когда упрощал код для примера в статье, то этот момент упустил.

Добавил условие в функции learn() у агента в примере в статье.

if len(memory_sample_tuples) > 0:
    loss_output = self.policy_explotate.learn(memory_sample_tuples)  

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

def __init__(self, inputSize: int, numActions: int, hiddenLayerSize: tuple=(256, 128)):

Тогда как в статье, я упростил код и использовал константы вместо передачи аргументов в функцию init. Это никак не должно повлиять на работу класса DQN.

По ошибке, рекомендую посмотреть код DQN(). Возможно, у вас не вызывается функция init у родительского класса nn.Module.

Я взял окружение gridworld из официального гайда библиотеки https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/

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


Быстрый фикс:

  1. Cкачать два файла из https://github.com/DarrMirr/reinforcement-learning-introduction/tree/main/src/environment

  2. Положить два скаченных файла к себе в проект

  3. Перед gym.make(...) добавить строчку class_GridWorldEnv.register() и соответствующий импорт class_GridWorldEnv.py

Спасибо за ссылку. С интересом почитал статью.

Я хотел лишь донести до вас мысль, что всё зависит от контекста.

В контексте коммерческой разработки: представленный пример однозначно потребуется доработать и точно учесть те предложения, что вы описали выше.

В контексте обучения: перегруженный и накрученный различными практиками пример будет только отвлекать обучаемого от основной темы.

Вы упомянули несколько хороших практик.

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

Также вы упомянули про MVC шаблон, где пользователь взаимодействует с Controller и меняет модель (через слои Service + Repository, которого в примере у меня нет), а потом изменяет View (для бекенда - это просто вернуть ответ UI приложению)

Дополнительно, мне очень понравилось про инфраструктурную роль. Ранее мне не доводилось слышать о таком подходе применимо к классам. Это интересно. Спасибо, что поделились.

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

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

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

Поэтому у меня были следующие задачи перед написанием примера:

  • Стартовый код примера должен умещаться в 1 класс и желательно в 1 метод

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

  • Количество операций в стартовом коде приложения не должно быть больше 3-5.

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

Подведу итог:

Образовательный пример - это не production-ready код. Он может нарушать некоторые хорошие практики, принятые в профессии, в угоду образовательной цели.

Постараюсь вам показать разницу в категориях мышления.

Процедурное мышление чем-то напоминает подход code first при проектировании API. Где сначала создаётся реализация, а затем разработчик смотрит на то, что у него по итогу получилось и описывает интерфейсы. И если на этом этапе приходит понимание, что получилось не очень удобная реализация, то начинается рефакторинг.

И при процедурном мышлении получается примерно также. Сначала код пишется в лоб, где фокус на реализацию алгоритма задачи. А затем разработчик смотрит на то, что получилось и как этим в дальнейшем пользоваться, то как правило это заканчивается рефакторигном (вынесение в классы, группировки в отдельные методы и т.п.), потому что фокус у него был другой (на реализацию алгоритма)

Мышление объектами напоминает подход contract first при проектировании API. Где сначала проектируются интерфейсы, а затем под них уже выполняется реализации.

Разработчик в этом случае выступает в роли архитектора, только не на уровне информационной системы (ИС) в целом, а на уровне приложения. Для такого разработчика программа - миниатюрная ИС со своими микросервисами и отношениями между ними. И микросервисы в данном случае выступают классы. Такой разработчик оперирует сущностями и контрактами между ними. Алгоритм реализации - это уже следующий этап, когда будут сформированы сущности и связи между ними. А количество строчек кода вообще перестаёт играть какое-либо значение.

Резюме:

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

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

P.S.
В заключении скажу, что я понимаю ваши вопросы, т.к. всех программистов обучают писать код императивным стилем. А такой стиль кодирования формирует процедурное мышление. Я пришёл к мышлению объектами (сущностями, если быть более точным), когда стал изучать функциональное программирование. По началу, мне оно показалось полным бредом, пока я не начал сквозь боль и неприятие учиться этим пользоваться. И после этого у меня началась формироваться новая категория мышления, т.к. я осознал, что в этом есть определённый смысл.

Класс, который следует концепции Rich объект (в терминах DDD) представляет собой класс-гибрид (я упоминал об этом в статье). Он сочетает в себе сразу несколько типов. В основе Rich объекта лежит Дата-класс, в который добавляется, как минимум Класс-исполнитель.

Уместность зависит от категории мышления программиста.

Программист, который думает процедурно, то он будет писать код примерно, как в этом примере:

public class MathService {

    public String multiply(String strNumber1, String strNumber2) {
        int num1 = Integer.parseInt(strNumber1);
        int num2 = Integer.parseInt(strNumber2);
        int result = num1 * num2;
        String strResult = new Integer(result).toString();
        return strResult;
    }
}

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

Программист, который думает объектами, то он будет писать код примерно, как в этом примере:

public class MathWebService {
    private final NumberConverter numberConverter = new NumberConverter(); // для простоты DI не буду использовать в примере.
    private final MathOperations mathOperations = new MathOperations(); // для простоты DI не буду использовать в примере.

    public String multiplyFeature(String strNumber1, String strNumber2) {
        int num1 = numberConverter.toInt(strNumber1);
        int num2 = numberConverter.toInt(strNumber2);
        int result = mathOperations.multiply(num1, num2);
        String strResult = numberConverter.toString(result);
        return strResult;
    }
}

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

Если программист тяготеет к процедурному мышлению. То он вполне естественно испытывает диссонанс, увидев метод из одной строчки кода, т.к. в его категории мышления - группировка кода из одного метода лишена здравого смысла.

Объясните мне не русскому что означает на русском языке слово ментор я такого в словарях русского языка почему то не нашел

Обычно ментор = наставник.

Более подробно с описанием из разных толковых словарей можно посмотреть здесь: https://gufo.me/dict/kuznetsov/ментор

Насчёт примера.

Цель моего примера исключительно образовательная: показать работу принципов. Всё, что не касается этой цели было намерено убрано или упрощено.

А состояние DTO меняется после создания?)

Такое может быть. Например, в интеграционных-сервисах, которые обогащают DTO данными, полученных из других источников, прежде чем прокинуть DTO дальше другому сервису.

Насчёт примера.
Цель моего примера исключительно образовательная: показать работу принципов. Всё, что не касается этой цели было намерено убрано или упрощено.

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

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

Rogue Lords тоже стоит в wishlist'е. А вот ArtStation, к сожалению, у меня не открылся. Видимо нужен впн...

Попробуйте, возможно, ваше мнение изменится.

Я в пятых героев тоже наиграл не мало часов. Но Герои и Disciples хоть и близкие по жанру игры, но по механикам игры довольно разные.

Кампанию можно проходить с модом. Я сейчас так и делаю :-)

Приятной вам игры. Если будет возможность, поделитесь своими впечатлениями после игры.

>Хотя некоторая трава, на вкус, слишком яркой стала

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

1

Information

Rating
903-rd
Registered
Activity