...

суббота, 22 июня 2019 г.

Официальный сайт Node.js теперь на русском

nodejs

По горячим следам, наконец-то, принятого пулл-реквеста, спешу объявить что официальный сайт Node.js теперь доступен на русском языке.


Предистория

Пару месяцев назад, я открыл сайт nodejs.org, где с английской версии был перенаправлен на украинскую https://nodejs.org/uk. Я родился и живу в Украине, следовательно, никаких нечитабельных иероглифов на экране я не увидел, но я заинтересовался вопросом:


Каким образом сайт решил мне предложить именно этот вариант перевода? Язык системы и браузера я обычно ставлю Английский или Русский, и очень интересно почему вместо них я получил именно Украинский вариант.

Быстро покопавшись в исходном коде на GitHub, я не смог найти никаких привязок к часовому поясу или местоположению, поэтому я вернулся на сайт. Поиски меню выбора языка не увенчались успехом, поэтому я решил сделать так, как поступил бы каждый уважающий себя web-разработчик и поменял путь с nodejs.org/uk на nodejs.org/ru. Но в результате я получил только 404-страницу, чему был удивлен. Перепроверив правильность написания пути, а также, на всякий случай, протестировав nodejs.org/rus, я получал один и тот же результат. Я снова отправился на GitHub, но теперь, чтобы найти правильный путь для русской версии сайта.

И вот что я нашел:


  1. Папка с русскими переводами попросту отсутствует в /locale
  2. Русскоязычное комьюнити неактивно более трех лет и отмечено как устаревшее

Собственно именно в этот момент времени я и решил что могу помочь с переводом.


Реализация

О самом процессе перевода сказать нечего ― берешь, да делаешь. В репозитории есть инструкции и рекомендации на эту тему. Трудности возникли там, где их не ждали ― в самом конце.

Закончив перевод я создал pull request прямо в главный репозиторий, что противоречит правилам, но другого варианта у меня не было, ввиду отсутствия налаженного процесса и русского комьюнити в целом.

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


Ценность

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

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

Я не знаю правильного ответа, ценна эта работа или нет, я просто перевел потому что могу.


Следующие шаги

Данная версия перевода, само собой, несовершенна и конечно же нуждается в исправлениях и улучшениях. Я планирую работать над этим и дальше и приглашаю вас поучаствовать. Так как создание pull request'ов в главный репозиторий противоречит рекомендациям по совместной работе nodejs, на данный момент внесение правок в перевод проблематично. Я уже создал issue касательно дальнейшей судьбы русскоязычного комьюнити nodejs, которое и определит процесс внесения правок.

Let's block ads! (Why?)

[Из песочницы] Создаем прототип для Sentiment Analysis с помощью Python и TextBlob

image

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

В этой статье речь пойдет как раз о прототипе. Который был создан через некоторое время после разговора с Product Manager: а почему бы нам не «пощупать» Machine Learning? В частности, NLP и Sentiment Analysis?
«А почему бы и нет?» — ответил я. Все-таки занимаюсь backend-разработкой более 15 лет, люблю работать с данными и решать проблемы производительности. Но мне еще предстояло узнать, «насколько глубока кроличья нора».

Выделяем компоненты


Чтобы как-то очертить набор компонентов, реализующих логику нашего ML-ядра, взглянем на простой пример реализации сентимент-анализа, один из множества, доступных на GitHub.
Один из примеров реализации сентимент-анализа на Python
import collections
import nltk
import os
from sklearn import (
    datasets, model_selection, feature_extraction, linear_model
)

def extract_features(corpus):
    '''Extract TF-IDF features from corpus'''
    # vectorize means we turn non-numerical data into an array of numbers
    count_vectorizer = feature_extraction.text.CountVectorizer(
        lowercase=True,  # for demonstration, True by default
        tokenizer=nltk.word_tokenize,  # use the NLTK tokenizer
        stop_words='english',  # remove stop words
        min_df=1  # minimum document frequency, i.e. the word must appear more than once.
    )
    processed_corpus = count_vectorizer.fit_transform(corpus)
    processed_corpus = feature_extraction.text.TfidfTransformer().fit_transform(
        processed_corpus)

    return processed_corpus

data_directory = 'movie_reviews'
movie_sentiment_data = datasets.load_files(data_directory, shuffle=True)
print('{} files loaded.'.format(len(movie_sentiment_data.data)))
print('They contain the following classes: {}.'.format(
    movie_sentiment_data.target_names))

movie_tfidf = extract_features(movie_sentiment_data.data)

X_train, X_test, y_train, y_test = model_selection.train_test_split(
    movie_tfidf, movie_sentiment_data.target, test_size=0.30, random_state=42)

# similar to nltk.NaiveBayesClassifier.train()
model = linear_model.LogisticRegression()
model.fit(X_train, y_train)
print('Model performance: {}'.format(model.score(X_test, y_test)))

y_pred = model.predict(X_test)
for i in range(5):
    print('Review:\n{review}\n-\nCorrect label: {correct}; Predicted: {predict}'.format(
        review=X_test[i], correct=y_test[i], predict=y_pred[i]
    ))



Разбирать такие примеры — это отдельный челлендж для разработчика.
Всего лишь 45 строк кода, и сразу 4 (четыре, Карл!) логических блока:
  1. Загрузка данных для обучения модели (строки 25-26)
  2. Подготовка загруженных данных — feature extraction (строки 31-34)
  3. Создание и обучение модели (строки 36-39)
  4. Тестирование обученной модели и вывод результата (строки 41-45)

Каждый из этих пунктов достоин отдельной статьи. И уж точно требует оформления в отдельном модуле. Хотя бы для нужд юнит-тестирования.

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

Благо, для того, чтобы быстро начать с NLP, есть готовое решение – библиотеки NLTK и TextBlob. Второе является оберткой над NLTK, которая делает рутинную работу – делает feature extraction из тренировочного набора, а затем обучает модель при первом запросе классификации.

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

Готовим данные


Загружаем данные


Если говорить о прототипе, то загрузка данных из CSV/TSV файла элементарна. Вы просто вызываете функцию read_csv из библиотеки pandas:
import pandas as pd
data = pd.read_csv(data_path, delimiter)


Но это не будут данные, готовые к использованию в модели.

Во-первых, если немного абстрагироваться от csv-формата, то нетрудно ожидать, что каждый источник будет предоставлять данные со своими особенностями, и, следовательно, нам потребуется некая, зависящая от источника, подготовка данных. Даже для простейшего случая CSV-файла, чтобы просто его распарсить, нам надо знать разделитель.

Кроме этого, следует определить, какие записи являются позитивными, а какие негативными. Конечно, это информация указана в аннотации к датасетам, которые мы хотим использовать. Но дело в том, что в одном случае признаком pos/neg является 0 или 1, в другом – логическое True/False, в третьем — это просто строка pos/neg, а в каком-то случае вообще кортеж целых чисел от 0 до 5. Последнее актуально для случая мультиклассовой классификации, но кто сказал, что такой набор данных нельзя использовать для бинарной классификации? Нужно просто адекватно обозначить границу позитивного и негативного значения.

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

Итак, можно выделить три функции, необходимых нам на этапе загрузки данных:

  1. Подключение к источнику данных – для CSV, в нашем случае это реализовано внутри функции read_csv;
  2. Поддержка особенностей формата;
  3. Предварительная подготовка данных.

Вот так это выглядит в коде.
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import logging

log = logging.getLogger()

class CsvSentimentDataLoader():

    def __init__(self, file_path, delim, text_attr, rate_attr, pos_rates):
        self.data_path = file_path
        self.delimiter = delim
        self.text_attr = text_attr
        self.rate_attr = rate_attr
        self.pos_rates = pos_rates

    def load_data(self):
        # Здесь данные вычитываются из csv или tsv файла
        data = pd.read_csv(self.data_path, self.delimiter)
        data.head()

       # Отбрасываются все колонки, 
       # кроме текста и классифицирующего атрибута        
       data = data[[self.text_attr, self.rate_attr]]

       # Значения классифицирующего атрибута 
       # приводятся к текстовым значениям ‘pos’ и ‘neg’
        data[self.rate_attr] = np.where(
            data[self.rate_attr].isin(self.pos_rates), 'pos', 'neg')

        return data


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

Сама загрузка происходит в методе load_data.

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


Ок, мы загрузили данные, но нам их еще надо разделить на тренировочный и тестовый наборы.

Делается это функцией train_test_split из библиотеки sklearn. Эта функция может принимать на вход множество параметров, определяющих, как именно этот dataset будет разделен на train и test. Эти параметры значительно влияют на получаемые тренировочные и тестовые наборы, и, вероятно, нам будет удобно сделать класс (назовем его SimpleDataSplitter), который будет управлять этими параметрами и агрегировать в себе вызов этой функции.

from sklearn.model_selection import train_test_split # to split the training and testing data
import logging

log = logging.getLogger()

class SimpleDataSplitter():

    def __init__(self, text_attr, rate_attr, test_part_size=.3):
        self.text_attr = text_attr
        self.rate_attr = rate_attr
        self.test_part_size = test_part_size
    
    def split_data(self, data):
        x = data[self.text_attr]
        y = data[self.rate_attr]

        x_train, x_test, y_train, y_test = train_test_split(
            x, y, test_size = self.test_part_size)

        return x_train, x_test, y_train, y_test 


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

Датасеты


Для обучения модели я использовал свободно доступные наборы данных в формате CSV:
И чтобы было еще чуть удобнее, для каждого из датасетов я сделал класс, который загружает данные из соответствующего CSV-файла и разбивает их на тренировочный и тестовый наборы.
import os
import collections
import logging
from web.data.loaders import CsvSentimentDataLoader
from web.data.splitters import SimpleDataSplitter, TdIdfDataSplitter

log = logging.getLogger()

class AmazonAlexaDataset():

    def __init__(self):
        self.file_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'amazon_alexa/train.tsv'))
        self.delim = '\t'
        self.text_attr = 'verified_reviews'
        self.rate_attr = 'feedback'
        self.pos_rates = [1]

        self.data = None
        self.train = None
        self.test = None

    def load_data(self):
        loader = CsvSentimentDataLoader(self.file_path, self.delim, self.text_attr, self.rate_attr, self.pos_rates)
        splitter = SimpleDataSplitter(self.text_attr, self.rate_attr, test_part_size=.3)

        self.data = loader.load_data()
        x_train, x_test, y_train, y_test = splitter.split_data(self.data)

        self.train = [x for x in zip(x_train, y_train)]
        self.test = [x for x in zip(x_test, y_test)] 


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

Плюс отдельные компоненты гораздо удобнее при юнит-тестировании.

Тренируем модель


Модель обучается довольно долго. И это надо делать один раз, при старте приложения.
Для этих целей был сделан небольшой враппер, позволяющий загрузить и подготовить данные, а также обучить модель в момент инициализации приложения.
class TextBlobWrapper():

    def __init__(self):
        self.log = logging.getLogger()
        self.is_model_trained = False
        self.classifier = None

    def init_app(self):
        self.log.info('>>>>> TextBlob initialization started')
        self.ensure_model_is_trained()
        self.log.info('>>>>> TextBlob initialization completed')

    def ensure_model_is_trained(self):
        if not self.is_model_trained:

            ds = SentimentLabelledDataset()
            ds.load_data()

            # train the classifier and test the accuracy
            self.classifier = NaiveBayesClassifier(ds.train)
            acr = self.classifier.accuracy(ds.test)
            self.log.info(str.format('>>>>> NaiveBayesClassifier trained with accuracy {}', acr))           

            self.is_model_trained = True

        return self.classifier


Сначала получаем тренировочные и тестовые данные, затем делаем feature extraction, и наконец обучаем классификатор и проверяем точность на тестовом наборе.

Тестируем


При инициализации получаем лог, судя по которому, данные загрузились и модель была успешно обучена. Причем обучена с весьма неплохой (для начала) точностью – 0.8878.

image

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

Причина этого — в данных обучающего набора. Количество позитивных отзывов в сете – более 90 %. Соответственно, при точности модели около 88 % негативные отзывы просто попадают в ожидаемые 12% неверных классификаций.

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

Чтобы действительно убедиться в этом, я сделал юнит-тест, который прогоняет классификацию отдельно для 100 позитивных и 100 негативных фраз из другого набора данных — для тестирования я взял Sentiment Labelled Sentences Data Set от Калифорнийского университета.

    @loggingtestcase.capturelogs(None, level='INFO')
    def test_classifier_on_separate_set(self, logs):
        tb = TextBlobWrapper() # Going to be trained on Amazon Alexa dataset 
        ds = SentimentLabelledDataset() # Test dataset
        ds.load_data()

        # Check poisitives
        true_pos = 0
        data = ds.data.to_numpy()

        seach_mask = np.isin(data[:, 1], ['pos'])
        data = data[seach_mask][:100]

        for e in data[:]:
            # Model train will be performed on first classification call
            r = tb.do_sentiment_classification(e[0])
            if r == e[1]:
                true_pos += 1

        self.assertLessEqual(true_pos, 100)
        print(str.format('\n\nTrue Positive answers - {} of 100', true_pos))


Алгоритм для тестирования классификации позитивных значений следующий:
  • Загружаем тестовые данные;
  • Берем 100 записей с меткой ‘pos’
  • Каждую из них прогоняем через модель и подсчитываем кол-во верных результатов
  • Выводим итоговый результат в консоль

Аналогично делается подсчет для негативных комментариев.
Результат
image

Как и предполагалось, все негативные комментарии распознались как позитивные.

А если натренировать модель на датасете, использованном для тестирования – Sentiment Labelled? Там распределение негативных и позитивных комментариев – ровно 50 на 50.

Меняем код и тест, запускаем
image

Уже что-то. Фактическая точность на 200 записей из стороннего набора – 76%, при точности классификации негативных комментариев – 79%.

Конечно, 76% — сгодится для прототипа, но недостаточно для продакшена. Это значит, что потребуется предпринимать дополнительные меры для повышения точности алгоритма. Но это уже тема для другого доклада.

Итоги


Во-первых, получилось приложение с десятком классов и 200+ строк кода, что несколько больше исходного примера на 30 строк. И следует быть честным — это лишь наметки на структуру, первое прояснение границ будущего приложения. Прототип.

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

Следующая вещь, которая может поставить новичка в ступор – данные не менее важны, чем выбранная модель. Это было наглядно показано.

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

Как по мне, все это следует учитывать еще при проектировании архитектуры и выстраивании процессов разработки.

В общем, «кроличья нора» оказалась не только весьма глубокой, но и чрезвычайно хитро проложенной. Но тем интереснее для меня, как разработчика, изучать эту тему в дальнейшем.

Let's block ads! (Why?)

[Из песочницы] Мой подход к реализации делегатов в C++: вызов функции с неизвестными параметрами во время выполнения

Предыстория


Мне нравится язык C++. Я бы даже сказал, что это мой любимый язык. Кроме того, для своих разработок я использую технологии .NET, и многие идеи в нём, по моему мнению, просто восхитительны. Однажды мне пришла в голову идея – как реализовать некоторые средства рефлексии и динамического вызова функций в C++? Очень уж хотелось, чтобы C++ тоже обладал таким преимуществом CLI, как вызов делегата с неизвестным количеством параметров и их типов. Это может пригодиться, например, когда заранее неизвестно, какие типы данных нужны функции, которую нужно вызвать.

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

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


Конечно, это главная проблема с C++, которая решается не так уж и просто. Конечно, в C++ есть средство, унаследованное из C – varargs, и, скорее всего, это первое, что придёт на ум… Однако они не подходят, во-первых, из-за своей типонебезопасной природы (как и многие вещи из C), во-вторых, при использовании таких аргументов надо точно заранее знать, какие у аргументов типы. Впрочем, почти наверняка, это ещё не все проблемы с varargs. В общем, это средство нам здесь не помощник.

А теперь перечислю средства, которые помогли мне решить эту проблему.

std::any


Начиная с C++17, в языке появился замечательный-контейнер-хранилище для чего угодно – некое отдалённое подобие System.Object в CLI – это std::any. Этот контейнер действительно может хранить что угодно, да ещё как: эффективно! – стандарт рекомендует маленькие объекты хранить непосредственно в нём, большие уже можно хранить в динамической памяти (хотя такое поведение не является обязательным, корпорация Microsoft в своей реализации C++ так и сделала, что не может не радовать). А подобием лишь его можно назвать потому, что System.Object участвует в отношениях наследования («is a»), а std::any – участвует в отношениях принадлежности («has a»). Кроме данных, контейнер содержит указатель на объект std::type_info – RTTI о типе, объект которого «лежит» в контейнере.

Для контейнера выделен целый заголовочный файл <any>.

Чтобы «вытащить» объект из контейнера, нужно использовать шаблонную функцию std::any_cast(), которая возвращает ссылку на объект.
Пример использования:

#include <any>
void any_test()
{
        std::any obj = 5;
        int from_any = std::any_cast<int>(obj);
}

Если запрашиваемый тип не совпадает с тем, что имеет объект внутри контейнера, тогда выбрасывается исключение std::bad_any_cast.

Кроме классов std::any, std::bad_any_cast и функции std::any_cast, в заголовочном файле есть шаблонная функция std::make_any, аналогичная std::make_shared, std::make_pair и другим функциям этого рода.

RTTI


Безусловно, практически нереально в C++ было бы реализовать динамический вызов функций без информации о типах во времени выполнения. Ведь надо же как-то проверять, правильные типы переданы, или нет.

Примитивная поддержка RTTI в C++ есть довольно давно. Вот только в том-то и дело, что примитивная – мы мало что можем узнать о типе, разве только декорированное и недекорированное имена. Кроме того, мы можем сравнивать типы друг с другом.

Обычно понятие «RTTI» применяется в связи с полиморфными типами. Однако здесь мы будем использовать этот термин в более широком смысле. Например, будем учитывать тот факт, что информация о типе во время выполнения есть у каждого типа (правда, получить её можно только статически, во время компиляции, в отличие от полиморфных типов). Поэтому сравнивать типы даже неполиморфных типов (простите за тавтологию) можно (и нужно) во время выполнения.
Доступ к RTTI можно получить с помощью класса std::type_info. Этот класс находится в заголовочном файле <typeinfo>. Ссылку на объект этого класса можно получить (по крайней мере, пока) лишь с помощью оператора typeid().

Шаблоны


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

Шаблоны – это очень обширная тема, и в рамках статьи раскрыть её не удастся, да и не нужно это. Будем считать, что читатель понимает, о чём речь. Какие-то неясные моменты будут раскрыты в процессе.

Упаковка аргументов с последующим вызовом


Итак, у нас есть некая функция, принимающая на вход несколько параметров.

Продемонстрирую набросок кода, который объяснит мои намерения.

#include <Variadic_args_binder.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <any>

int f(int a, std::string s)
{
        std::cout << "int: " << a << "\nstring: " << s << std::endl;
        return 1;
}

void demo()
{
        std::vector<std::any> params;
        params.push_back(5);
        params.push_back(std::string{ "Hello, Delegates!" });
        delegates::Variadic_args_binder<int(*)(int, std::string), int, std::string> binder{ f, params };
        binder();
}

Возможно, вы спросите – как это возможно? Название класса Variadic_args_binder подсказывает, что объект связывает функцию и аргументы, которые нужно ей передать при вызове. Таким образом, остаётся лишь вызвать этот связыватель как функцию без параметров!
Так это выглядит снаружи.

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

fun_ptr(param1, param2, …, paramN);

Так устроен C++. И это всё сильно усложняет.

Тут справится лишь шаблонная магия!

Основная идея – создавать рекурсивные типы, хранящие на каждом уровне вложенности один из аргументов или функцию.

Итак, объявим класс _Tagged_args_binder:

namespace delegates::impl
{
        template <typename Func_type, typename... T>
        class _Tagged_args_binder;
}

Чтобы удобно «переносить» пакеты типов, создадим вспомогательный тип Type_pack_tag (зачем это понадобилось, скоро станет понятно):
template <typename... T>
struct Type_pack_tag
{
};

Теперь создаём специализации класса _Tagged_args_binder.

Начальные специализации


Как известно, чтобы рекурсия не была бесконечной, необходимо определить граничные случаи.
Следующие специализации являются начальными. Для упрощения приведу специализации лишь для нессылочных типов и правосторонних ссылочных типов (rvalue reference).
Специализация для непосредственно параметров-значений:
template <typename Func_type, typename T1, typename... Types_to_construct>
class _Tagged_args_binder<Func_type, Type_pack_tag<T1, Types_to_construct...>, Type_pack_tag<>>
{
public:
        static_assert(!std::is_same_v<void, T1>, "Void argument is not allowed");

using Ret_type = std::invoke_result_t<Func_type, T1, Types_to_construct...>;

        _Tagged_args_binder(Func_type func, std::vector<std::any>& args)
                : ap_arg{ std::move(unihold::reference_any_cast<T1>(args.at(0))) },
                ap_caller_part{ func, args } { }

        auto operator()()
        {
                if constexpr(std::is_same_v<void, Ret_type>)
                {
                        ap_caller_part(std::move(ap_arg));
                        return;
                }
                else
                {
                        return std::forward<Ret_type>(ap_caller_part(std::move(ap_arg)));
                }
        }

        auto operator()() const
        {
                if constexpr (std::is_same_v<void, Ret_type>)
                {
                        ap_caller_part(std::move(ap_arg));
                        return;
                }
                else
                {
                        return std::forward<Ret_type>(ap_caller_part(std::move(ap_arg)));
                }
        }

private:
        _Tagged_args_binder<Func_type, Type_pack_tag<Types_to_construct...>, Type_pack_tag<T1>> ap_caller_part;
        T1 ap_arg;
};

Здесь хранятся первый аргумент вызова ap_arg и остальная часть рекурсивного объекта ap_caller_part. Обратите внимание, что тип T1 «переместился» из первого пакета типов в этом объекте во второй в «хвосте» рекурсивного объекта.

Специализация для rvalue-ссылок:

template <typename Func_type, typename T1, typename... Types_to_construct>
class _Tagged_args_binder<Func_type, Type_pack_tag<T1&&, Types_to_construct...>, Type_pack_tag<>>
{
        using move_ref_T1 = std::add_rvalue_reference_t<std::remove_reference_t<T1>>;
public:
        using Ret_type = std::invoke_result_t<Func_type, move_ref_T1, Types_to_construct>;

        _Tagged_args_binder(Func_type func, std::vector<std::any>& args)
                : ap_arg{ std::move(unihold::reference_any_cast<T1>(args.at(0))) },
                ap_caller_part{ func, args }
        {
        }

        auto operator()()
        {
                if constexpr (std::is_same_v<void, Ret_type>)
                {
                        ap_caller_part(std::move(unihold::reference_any_cast<T1>(ap_arg)));
                }
                else
                {
                        return std::forward<Ret_type>(ap_caller_part(std::move(unihold::reference_any_cast<T1>(ap_arg))));
                }
        }

        auto operator()() const
        {
                if constexpr (std::is_same_v<void, Ret_type>)
                {
                        ap_caller_part(std::move(unihold::reference_any_cast<T1>(ap_arg)));
                }
                else
                {
                        return std::forward<Ret_type>(ap_caller_part(std::move(unihold::reference_any_cast<T1>(ap_arg))));
                }
        }

private:
        _Tagged_args_binder<Func_type, Type_pack_tag<Types_to_construct...>, Type_pack_tag<move_ref_T1>> ap_caller_part;
        std::any ap_arg;
}; 

Шаблонные «правосторонние» ссылки – на самом деле не являются правосторонними значениями. Это так называемые «универсальные ссылки», которые, в зависимости от типа T1, становятся то T1&, то T1&&. Поэтому приходится использовать обходные пути: во-первых, так как определены специализации для обеих видов ссылок (не совсем корректно сказано, по уже озвученной причине) и для нессылочных параметров, при инстанцировании шаблона будет выбрана именно нужная специализация, даже если это правосторонняя ссылка; во-вторых – для передачи типа T1 из пакета в пакет используется исправленная версия move_ref_T1, превращённая в настоящую rvalue-ссылку.

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

Конечная специализация

template <typename Func_type, typename... Param_type>
class _Tagged_args_binder<Func_type, Type_pack_tag<>, Type_pack_tag<Param_type...>>
{
public:
        using Ret_type = std::invoke_result_t<Func_type, Param_type...>;

        inline _Tagged_args_binder(Func_type func, std::vector<std::any>& args)
                : ap_func{ func } { }
        
        inline auto operator()(Param_type... param)
        {
                if constexpr(std::is_same_v<void, decltype(ap_func(std::forward<Param_type>(param)...))>)
                {
                        ap_func(std::forward<Param_type>(param)...);
                        return;
                }
                else
                {
                        return std::forward<Ret_type>(ap_func(std::forward<Param_type>(param)...));
                }
        }

        inline auto operator()(Param_type... param) const
        {
                if constexpr(std::is_same_v<void, Ret_type>)
                {
                        ap_func(param...);
                        return;
                }
                else
                {
                        return std::forward<Ret_type>(ap_func(param...));
                }
        }

private:
        Func_type ap_func;
};

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

Обратите внимание, как используется здесь Type_pack_tag. Все типы параметров теперь собраны в левом пакете. Это значит, что все они обработаны и упакованы.

Теперь, думаю, становится понятно, зачем нужно было использовать именно Type_pack_tag. Дело в том, язык не позволил бы использовать рядом два пакета типов, например, вот так:

template <typename Func_type, typename T1, typename... Types_to_construct, typename... Param_type>
class _Tagged_args_binder<Func_type, T1, Types_to_construct..., Param_type...>
{
};

поэтому приходится разделять их на два раздельных пакета внутри двух типов. Кроме того, надо как-то отделять обработанные типы от ещё не обработанных.

Промежуточные специализации


Из промежуточных специализаций напоследок приведу специализацию, опять-таки, для типов-значений, остальное по аналогии:
template <typename Func_type, typename T1, typename... Types_to_construct, typename... Param_type>
class _Tagged_args_binder<Func_type, Type_pack_tag<T1, Types_to_construct...>, Type_pack_tag<Param_type...>>
{
public:
        using Ret_type = std::invoke_result_t<Func_type, Param_type..., T1, Types_to_construct...>;

        static_assert(!std::is_same_v<void, T1>, "Void argument is not allowed");

        inline _Tagged_args_binder(Func_type func, std::vector<std::any>& args)
                : ap_arg{ std::move(unihold::reference_any_cast<T1>(args.at(sizeof...(Param_type)))) },
                ap_caller_part{ func, args } { }

        inline auto operator()(Param_type... param)
        {
                if constexpr (std::is_same_v<void, Ret_type>)
                {
                        ap_caller_part(std::forward<Param_type>(param)..., std::move(ap_arg));
                        return;
                }
                else
                {
                        return std::forward<Ret_type>(ap_caller_part(std::forward<Param_type>(param)..., std::move(ap_arg)));
                }
        }

        inline auto operator()(Param_type... param) const
        {
                if constexpr (std::is_same_v<void, Ret_type>)
                {
                        ap_caller_part(std::forward<Param_type>(param)..., std::move(ap_arg));
                }
                else
                {
                        return std::forward<Ret_type>(ap_caller_part(std::forward<Param_type>(param)..., std::move(ap_arg)));
                }
        }

private:
        _Tagged_args_binder<Func_type,
                Type_pack_tag<Types_to_construct...>,
                Type_pack_tag<Param_type..., T1>> ap_caller_part;
        T1 ap_arg;
};

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

Класс-связыватель


Класс _Tagged_args_binder не предназначен для непосредственного использования, что я хотел подчеркнуть одинарным подчёркиванием в начале его названия. Поэтому приведу код небольшого класса, являющегося своего рода «интерфейсом» к этому некрасивому и неудобному в использовании типу (в котором, однако, используются довольно необычные приёмы C++, что придаёт ему некоторый шарм, на мой взгляд):
namespace cutecpplib::delegates
{
        template <typename Functor_type, typename... Param_type>
        class Variadic_args_binder
        {
                using binder_type = impl::_Tagged_args_binder<Functor_type, Type_pack_tag<Param_type...>, Type_pack_tag<>>;

        public:
                using Ret_type = std::invoke_result_t<binder_type>;

                inline Variadic_args_binder(Functor_type function, Param_type... param)
                        : ap_tagged_binder{ function, param... } { }

                inline Variadic_args_binder(Functor_type function, std::vector<std::any>& args)
                        : ap_tagged_binder{ function, args } { }

                inline auto operator()()
                {
                        return ap_tagged_binder();
                }

                inline auto operator()() const
                {
                        return ap_tagged_binder();
                }

        private:
                binder_type ap_tagged_binder;
        };
}


Соглашение unihold – передача ссылок внутри std::any


Внимательный читатель наверняка заметил, что в коде используется функция unihold::reference_any_cast(). Эта функция, а также её аналог unihold::pointer_any_cast(), разработаны для реализации соглашения библиотеки: аргументы, которые необходимо передать по ссылке, передаются по указателю в std::any.

Функция reference_any_cast всегда возвращает ссылку на объект, хранится ли в контейнере сам объект или только указатель на него. Если std::any содержит в себе объект, то возвращается ссылка на этот объект внутри контейнера; если же содержит указатель – то возвращается ссылка на объект, на который указывает указатель.

Для каждой из функций есть варианты константного std::any и перегруженные версии для определения того, является ли контейнер std::any владельцем объекта или же содержит лишь указатель.

Функции нужно специализировать явно типом хранимого объекта, так же, как преобразования типов C++ и подобные им шаблонные функции.

Код этих функций:

template <typename T>
std::remove_reference_t<T>& unihold::reference_any_cast(std::any& wrapper)
{
        bool result;
        return reference_any_cast<T>(wrapper, result);
}

template <typename T>
const std::remove_reference_t<T>& unihold::reference_any_cast(const std::any& wrapper)
{
        bool result;
        return reference_any_cast<T>(wrapper, result);
}

template <typename T>
std::remove_reference_t<T>& unihold::reference_any_cast(std::any& wrapper, bool& is_owner)
{
        auto ptr = pointer_any_cast<T>(&wrapper, is_owner);
        if (!ptr)
                throw std::bad_any_cast{ };
        return *ptr;
}

template <typename T>
const std::remove_reference_t<T>& unihold::reference_any_cast(const std::any& wrapper, bool& is_owner)
{
        auto ptr = pointer_any_cast<T>(&wrapper, is_owner);
        if (!ptr)
                throw std::bad_any_cast{ };
        return *ptr;
}

template <typename T>
std::remove_reference_t<T>* unihold::pointer_any_cast(std::any* wrapper, bool& is_owner)
{
        using namespace std;
        using NR_T = remove_reference_t<T>; // No_reference_T
        // Указатель на указатель внутри wrapper
        NR_T** double_ptr_to_original = any_cast<NR_T*>(wrapper);
        // Указатель на копию объекта внутри wrapper
        NR_T* ptr_to_copy;
        if (double_ptr_to_original)
        {
                // Wrapper содержит указатель на оригинал объекта
                is_owner = false;
                return *double_ptr_to_original;
        }
        else if (ptr_to_copy = any_cast<NR_T>(wrapper))
        {
                // Wrapper содержит копию объекта
                is_owner = true;
                return ptr_to_copy;
        }
        else
        {
                throw bad_any_cast{};
        }
}

template <typename T>
const std::remove_reference_t<T>* unihold::pointer_any_cast(const std::any* wrapper, bool& is_owner)
{
        using namespace std;
        using NR_T = remove_reference_t<T>; // No_reference_T
        // Указатель на указатель внутри wrapper
        NR_T*const * double_ptr_to_original = any_cast<NR_T*>(wrapper);
        // Указатель на копию объекта внутри wrapper
        const NR_T* ptr_to_copy;
        //remove_reference_t<T>* ptr2 = any_cast<remove_reference_t<T>>(&wrapper);
        if (double_ptr_to_original)
        {
                // Wrapper содержит указатель на оригинал объекта
                is_owner = false;
                return *double_ptr_to_original;
        }
        else if (ptr_to_copy = any_cast<NR_T>(wrapper))
        {
                // Wrapper содержит копию объекта
                is_owner = true;
                return ptr_to_copy;
        }
        else
        {
                throw bad_any_cast{};
        }
}

template <typename T>
std::remove_reference_t<T>* unihold::pointer_any_cast(std::any* wrapper)
{
        bool result;
        return pointer_any_cast<T>(wrapper, result);
}

template <typename T>
const std::remove_reference_t<T>* unihold::pointer_any_cast(const std::any* wrapper)
{
        bool result;
        return pointer_any_cast<T>(wrapper, result);
}


Заключение


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

P.S. Использование RTTI будет демонстрироваться в следующей части.

Let's block ads! (Why?)

Адаптивный дизайн приложения под каждого пользователя

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

А что если уйти еще дальше и помимо контента предоставлять людям персонализированный UI?!

Теория


Концепция
  1. Приложение само понимает, чем ты часто пользуешься и выносит часто используемую функциональность на первый экран.
  2. Располагает элементы по степени значимости на странице так, чтобы вам не нужно было бы тянуться большим пальцем до него.
  3. В зависимости от того насколько часто этот элемент используется, его содержание тоже будет сильно отличаться
  4. Так же есть триггеры: пришло пуш уведомление, определенная дата или действие пользователя. Этот триггер имеет свой удельный вес, который присваивается отдельному элементу на короткое время.

Логика

Этап калибровки

Человек пользуется приложением.

А программа сама анализирует количество кликов на каждый элемент и дает элементам удельный вес.

Этап плавного внедрения

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

Этап проверки элемента

Мы анализируем частоту заходов и определяем достоин ли элемент того, чтобы остаться на главной странице.

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

Практика


Пример реализации приложения

Хороший пример это банковские приложения.

Почему?

  1. Они многофункциональные
  2. Большая часть функций мне как пользователю вообще не нужна, но другим они могут быть важней
  3. Некоторая часть функций может быть нужна, только в определенный момент
  4. Такими приложениями пользуются все, поэтому легче понять концепцию

Здесь я постараюсь показать на этапе эскизов как я вижу должно быть. Если пост будет интересен, то тогда я уже сделаю демо приложение на iOS.
Грубый эксиз приложения


Сценарии

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

Сценарий 1: Перевожу часто деньги одному и тому же человеку (младший брат, ребенок, жена).

Мы можем добавить блок с возможностью быстрого перевода именно ему.

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

2 уровень блока:

Здесь мы уже можем переводить непосредственно с самой ячейки, нажав на кнопку перевести

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

3 уровень блока

Сценарий 2 Раз в месяц я плачу за квартиру, здесь уже срабатывает триггер даты.
Приложение понимает, что примерно в это число каждый месяц я отдаю деньги за квартиру.
И логично нам показать именно этот блок именно в этот день на главном экране и после исполнения платежа его убрать.

Сценарий 3 Закрываю кредит после получения зп.

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

В блоке теперь появляется оплата кредита.

Сценарий 4 Использую чат с поддержкой

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

Сценарий 5 Вывожу деньги с расчетного счета на карту

Срабатывает триггер о поступлении денег р/с и я допустим всегда распределяю их между своими картами:

Я хотел донести мысль, что пользовательский опыт можно улучшить, пытаясь помочь ему выполнить то, что он хочет как можно быстрей, конечно это будет сложнее для нас как разработчиков, но это будет оценено нашими клиентами. Cкажите, что вы думаете о таком подходе?

Let's block ads! (Why?)

Какими могут быть вычислительные системы будущего

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



/ фото jesse orrico Unsplash

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

ДНК-компьютеры


Это — система, которая использует вычислительные возможности молекул ДНК. Нити ДНК состоят из четырех азотистых оснований: цитозина, аденина, гуанина и тимина. Связывая их в определенной последовательности, можно кодировать информацию. Для изменения данных используют специальные ферменты, которые с помощью химических реакций достраивают цепочки ДНК, а также разрезают и укорачивают их. Такие реакции можно проводить в разных частях молекулы одновременно, что позволяет выполнять параллельные вычисления.

Первый компьютер на базе ДНК представили в 1994 году. Профессор молекулярной биологии и компьютерных наук Леонард Адлеман (Leonard Adleman) использовал несколько пробирок с миллиардами молекул ДНК, чтобы попытаться решить задачу коммивояжера для графа с семью вершинами. Его вершины и ребра Адлеман обозначил фрагментами ДНК с двадцатью азотистыми основаниями, а затем применил метод полимеразной цепной реакции (ПЦР).

Недостатком компьютера Адлемана была его «узконаправленность». Он был заточен под решение одной задачи и не мог выполнять другие. С тех пор ситуация изменилась — в конце марта ученые из университета Мейнут и Калифорнийского технологического института представили компьютер, данные в который загружаются в виде последовательностей ДНК и могут быть перепрограммированы.

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

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

Нейроморфные процессоры


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

Впервые идея создания нейроморфных систем появилась еще в 1990-х. Но всерьез разработками в этой области занялись после 2000-х. Специалисты из IBM Research запустили проект SyNAPSE, целью которого была разработка компьютера с архитектурой, отличной от архитектуры фон Неймана. В рамках этого проекта компания спроектировала чип TrueNorth. Он эмулирует работу миллиона нейронов и 256 миллионов синапсов.

Над нейроморфными процессорами трудятся не только в IBM. Компания Intel с 2017 года разрабатывает чип Loihi. В его составе 130 тысяч искусственных нейронов и 130 млн синапсов. Год назад компания завершила разработку прототипа по 14-нм техпроцессу.

Нейроморфные устройства позволяют ускорить обучение нейросетей. Таким чипам, в отличие от классических процессоров, не нужно регулярно обращаться к регистрам или памяти за данными. Вся информация постоянно хранится в искусственных нейронах. Эта особенность позволит обучать нейронные сети локально (без подключения хранилищу со сводом тестовых данных).

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

Квантовые машины


Основу квантовых компьютеров составляют кубиты. Их работа основывается на принципах квантовой физики — запутанности и суперпозиции. Суперпозиция позволяет кубиту находиться в состоянии нуля и единицы одновременно. Запутанность — это явление, при котором состояния нескольких кубитов оказываются взаимосвязанными. Такой подход позволяет проводить операции с нулем и единицей одновременно.


/ фото IBM Research CC BY-NA

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

На сегодняшний день развитием квантовых вычислений занимается относительно небольшое число компаний. Среди них можно выделить IBM с их 50-кубитным квантовым компьютером, Intel с 49-кубитным и InoQ, которая тестирует 79-кубитное устройство. Также в этой области работают Google, Rigetti и D-Wave.

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

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

Хотя в начале года IBM представили квантовый компьютер, способный работать при комнатной температуре. Но купить аппарат пока нельзя, можно лишь арендовать его мощности через облачную платформу. Компания обещает, что в будущем этот компьютер сможет приобрести любой желающий, но когда это произойдет — пока неизвестно.



Материалы из нашего Telegram-канала:

Let's block ads! (Why?)

[Перевод] Мозг ускоряет восприятие, догадываясь о том, что будет дальше

Ваши ожидания формируют и ускоряют ваше восприятие. Новая модель, объясняющая этот эффект, предлагает обновить теории обработки сигналов.



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

Представьте, что вы взяли стакан, и думаете что внутри – яблочный сок, а потом, пригубив, обнаруживаете, что это имбирный эль. Даже если вы обычно любите содовую, на этот раз вкус кажется вам противным. Всё потому, что контекст и внутренние состояния, включая ожидание, влияют на то, как животные ощущают и обрабатывают информацию с органов чувств, поясняет Альфредо Фонтанини, нейробиолог из Университета Стони-Брук в Нью-Йорке. В данном случае ожидание не того стимула приводит к удивлению и отрицательной реакции.

Однако это влияние не ограничивается качеством восприятия. Среди прочих эффектов, настройка органов чувств на ожидание входных данных, хороших или плохих, может увеличить скорость обнаружения, определения и реакции на них животного.
Много лет назад Фонтанини с командой обнаружили прямые свидетельства этого эффекта ускорения во вкусовой коре – участке мозга, отвечающем за восприятие вкуса. С тех пор они пытаются найти в коре структуру, делающую этот эффект возможным. И вот им это удалось. В апреле 2019 они опубликовали свои открытия в журнале Nature Neuroscience: модель сети с определённой архитектурой, которая не только предлагает новые идеи о принципах работы ожидания, но и заходит на территорию более широких вопросов о том, как нейробиологи должны относиться к восприятию. Более того, выводы в чём-то совпадают с теорией принятия решений, утверждающей, что мозг не выстраивает решения постепенно, а принимает их скоропалительно.

Ускоренные чувства и активные состояния


Вкус, наименее изученное ощущение, был идеальной отправной точкой. После того, как вкус появляется на языке, проходит несколько сотен миллисекунд до того, как активность вкусовой коры начинает отражать входные данные. «В терминах работы мозга это ужасно долго, — сказал Дон Кац, нейробиолог из Брандейского университета в Массачусетсе (в лаборатории которого Фонтанини проходил постдокторантуру). – В визуальной коре всё происходит за малую долю этого времени», из-за чего у зрения гораздо труднее распознать эффект ожидания, который хотели изучать учёные.

В 2012 Фонтанини с коллегами провели эксперимент, в котором крысы слышали звук («предварительную подсказку»), а потом получали небольшую дозу пищи через трубку в пасти. Сам её вкус мог быть сладким, солёным, кислым или горьким, и в подсказке не было никакой информации касаемо его характера.

И всё равно было обнаружено, что в целом ожидание вкуса заставляло нейроны вкусовой коры распознавать стимул почти в два раза быстрее, по сравнению с тем, когда крысы получали пищу, не слыша предварительного звука. Задержка падала с примерно 200 мы до 120 мс.

Фонтанини хотел узнать, какая нейросеть теоретически позволит осуществлять ускорение кодирования. Он привлёк специалиста, не работавшего ранее в области вкуса: коллегу из Стони-Брук, нейробиолога Жанкарло ла Камеру, работавшего ранее над моделированием спонтанной активности мозга, возникающей даже при отсутствии стимулов.


Альфредо Фонтанини и Жанкарло ла Камера

В последние несколько десятилетий росла убеждённость в том, что большая часть активности сенсорных сетей генерируется внутри, а не вызывается внешними стимулами. Если сравнить активность зрительной коры животного в полной темноте с её активностью, когда животное осматривается, сложно будет найти в них отличия. Даже в отсутствии света наборы нейронов зрительной коры начинают активизироваться совместно, одновременно или же с предсказуемой периодичностью. Это взаимосвязанное срабатывание находится в т.н. метастабильном состоянии от нескольких сотен миллисекунд до нескольких секунд, а потом конфигурация активности меняется на другую. Метастабильность, или тенденция к тому, чтобы прыгать от одного мимолётного состояния к другому, продолжается после появления стимула, однако некоторые состояния часто проявляются чаще в связи с конкретным стимулом, и, следовательно, считаются «кодирующими состояниями».

Ла Камера и другие (в т.ч. и Кац) уже моделировали метастабильность, создавая то, что называется кластеризованной сетью. Внутри неё группы возбуждающих нейронов тесно связаны друг с другом, а тормозящие нейроны случайным образом соединены с возбуждающими, что оказывает широкий приглушающий эффект на всю систему. «Такая кластеризованная архитектура фундаментально важна для создания метастабильности», — сказал Фонтанини.

Фонтанини, ла Камера и их коллега, постдок Лука Маццукато (теперь работающий в Орегонском университете) обнаружили, что та же структура сети необходима и для воссоздания эффекта ожидания. В метастабильной модели кластеризованной архитектуры исследователи провели симуляцию предупреждающей подсказки, за которой следует определённый вкусовой стимул. В итоге они успешно воспроизвели схему ускоренного кодирования, которую Фонтанини наблюдал у крыс в 2012-м: переходы из одного метастабильного состояния в другое ускорялись, что давало системе возможность быстрее переходить в кодирующие состояния. Результаты работы показывают, что просто создав сеть для демонстрации метастабильных схем активности, «можно охватить множество нейрологических откликов при стимуляции вкусовых ощущений», — сказал Фонтанини.

Когда исследователи попытались смоделировать предупреждающие подсказки и стимулы в сети, не имеющей кластеризованных нейронов, им не удалось повторить результаты 2012 года. Поэтому «этот эффект возможен только в сетях определённого типа», сказал Кац.

Менее напряжённая прогулка


Открытие показалось примечательным, во-первых, поскольку дало идеи о том, какую архитектуру следует искать в реальной вкусовой коре – и, возможно, в других частях коры, отвечающей за органы чувств. Пока что нейробиологи спорят о том, как обрабатывается вкус: некоторые говорят, что одни определённые нейроны могут кодировать «сладкое», а другие «солёное», создавая характерные неврологические отклики для определённых вкусов. Другие связывают его с более широкими схемами активности; большинство нейронов реагирует на большинство вкусов, и получившаяся неврологическая схема грубо соответствует одному или другому вкусу. Работа Фонтанини и коллег поддерживает последнюю теорию, предсказывая, как именно должна выглядеть эта структура. Уже только одни скопления «обрисовывают множество свойств вкусовой коры, — сказал Фонтанини, — спонтанную активность, последовательность отзывов на вкус, эффект ожидания». Он надеется продолжать раскапывать историю формирования этих скоплений, и то, на какие иные виды нервной активности они влияют.

Также работа обрисовывает нейронное основание для ожиданий в мозге. Предупреждающая подсказка не просто возбуждает определённые нейроны или вызывает некий набор состояний, который затем кодирует стимул. Вместо этого ожидание изменяет динамику – конкретно, скорость переключения – всей системы.

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

То есть, ожидание делает сеть не такой прилипчивой. Оно позволяет совершить более лёгкую прогулку по направлению к состояниям, реально кодирующим вкус, но не даёт такой стабильности, чтобы система застряла в одном состоянии. Эта проблема часто преследует подобные кластеризованные сети: из-за этой группировки некоторые «траншеи» оказываются слишком глубокими, и система усиливает неверную информацию. Но эти открытия говорят, что для решения этой проблемы «сложная система вам не нужна», сказал Георг Келлер, нейробиолог, изучающий работу зрения в институте биомедицинских исследований им. Фридриха Мишера в Швейцарии.

Фонтанини и ла Камера надеются, что подобный механизм сможет объяснить работу других процессов, выводящих контекст за пределы ожиданий, например, внимания и обучения. Но, возможно, «наиболее важным последствием нашей работы будет перенос внимания со статической реакции нейронов, кодирующих те или иные реакции, на их динамическое поведение», — сказал ла Камера.

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

Но в данной работе всё не так. Результаты команды говорят в пользу другой идеи обработки сигналов, в которой «всё происходит одновременно, ещё до того, как прибудет сигнал о стимуле, — сказал Лесли Кэй, нейробиолог из Чикагского университета, занимающийся обонянием. – Выученная информация оказывается в области коры, формирует систему связанных между собой групп нейронов, обозначающих эту информацию, а потом вы влияете на неё при помощи ожиданий, в результате чего проявляется то, что эта система знает».

Внезапный порыв


Из модели следует, что процесс принятия решений не является плавным построением на основе полученной информации, а чем-то вроде последовательности озарений, прыжком нейронных флуктуаций. Кац использовал ту же модель, что и Фонтанини с ла Камера для поддержки идеи о том, что принятие решения «происходит во внезапном порыве».

Связь между этими «совершенно разными углами области вкуса» – работы Фонтанини над обработкой ощущений от органов чувств и его исследованием их дальнейшей обработки – оставляет Каца в состоянии «радостного предвкушения».

Она также подчёркивает необходимость отойти от концентрации на отдельных нейронах, реагирующих на определённые подсказки, и двигаться в сторону внутренних состояний и динамики для лучшего понимания работы сенсорных сетей – даже в случае самых базовых сенсорных стимулов. «Гораздо проще сказать, что нейрон увеличивает количество активаций, — сказал Анан Моран, нейробиолог из Тель-Авивского университета в Израиле. Но чтобы понять, как работают организмы, „нельзя учитывать только стимул, нужно считаться и с внутренним состоянием, — добавил он. – А это значит, что наше предыдущее представление о механизме, используемом мозгом для реализации ощущений, действий и так далее, необходимо пересмотреть“.

»Большая часть происходящего во вкусовой коре перед тем, как стимул её достигает, связана с его обработкой по приходу", — сказал Кац. В данном случае изучение того, как эти внутренние состояния изменяются под влиянием опыта или подсказки, открыло нам новую информацию о связности сети.

Теперь, сказал Моран, такая контекстная зависимость должна подвергнуться другим исследованиям восприятия и мышления. «Последний рубеж – это зрительная система. Подобная работа может поведать нам что-то интересное об обработке зрительной информации».

«У нас пока что нет хорошей, единой модели, объединяющей всю эту активность», — добавил он. Но это является «хорошей отправной точкой».

Let's block ads! (Why?)

[Перевод] Конференция DEFCON 25. Гарри Каспаров. «Последняя битва мозга». Часть 1

Для меня большая честь присутствовать здесь, но, пожалуйста, не нужно меня взламывать. Компьютеры и так меня ненавидят, так что мне нужно подружиться с как можно большим числом людей в этом зале. Хочу привести один маленький пустяк из моей биографии, интересный для американской аудитории. Я родился и вырос на самом юге страны, прямо рядом с Джорджией. Это на самом деле правда. Подождите секундочку, я же говорил, что компьютеры меня ненавидят!

Один слайд потерялся, но это действительно самый юг СССР, где я родился в республике, которая была расположена прямо по соседству с Республикой Джорджия (прим. переводчика: название штата Джорджия и республики Грузия по-английски звучит одинаково).

Если говорить о моей родине, забавно то, что моя последняя книга «Deep Thinking» была написана об искусственном интеллекте, о моем собственном опыте сражений с компьютерами, а книга, написанная за два года перед этим, называлась «Зима приближается». Это не было синопсисом «Игры тронов», речь шла о Владимире Путине и борьбе за свободный мир, но когда я проводил тур презентации этой книги, все хотели спросить меня о шахматах и компьютере IBM Deep Blue. Сейчас, когда я презентую книгу «Deep Thinking», все хотят спросить меня о Путине. Но я стараюсь придерживаться темы, и я уверен, что после этой презентации будут несколько вопросов, на которые я буду рад ответить. Я не политик, поэтому не уклоняюсь от ответов на вопросы.

Может показаться странным, что игра в шахматы, возникшая тысячи лет назад, Бог знает когда, является идеальной аналогией искусственного интеллекта, потому что когда мы говорим об AI, мы должны помнить, что буква I означает «интеллект», и нет ничего, что демонстрирует это лучше, чем шахматы.

Многие люди считают, что шахматы не более чем забава, которой предаются люди в кафе. Если посмотреть на творения Голливуда, то все играют в шахматы – инопланетяне, люди Х, Визард, вампиры. Моя любимая картина «Касабланка» с Хэмфри Богартом тоже про шахматы, и когда я пересматриваю этот фильм, мне всегда хочется встать в такую позицию, чтобы заглянуть внутрь экрана и увидеть, доску Богарта. Он играет французскую защиту, которая была очень популярна в начале 40-х годов. Я думаю, Богарт был довольно приличным шахматистом.

Хочу упомянуть, что Альфред Бине, один из соавторов IQ-теста конца 19 века, восхищался умом шахматистов и изучал его на протяжении многих лет. Поэтому не удивительно, что игра в шахматы привлекает тех, кто хотел создавать умные машины. Однако часто бывает так, что интеллектуальные машины, такие, как «Турок» фон Кемпелена, являются просто грандиозным надувательством. Но в конце 18 века этот шахматный автомат был большим чудом, он гастролировал по Европе и Америке и сражался с сильными и слабыми игроками, такими, как Франклин и Наполеон, но конечно, всё это был обман. «Турок» не был настоящей машиной, это была оригинальная механическая система из скользящих панелей и зеркал, внутри которой прятался сильный игрок – человек.

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

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

Интересно то, что создали основ компьютерного дизайна, такие как Алан Тьюринг и Клод Шеннон, проявляли большой интерес к шахматам. Они верили, что игра в шахматы может раскрыть секреты искусственного интеллекта. И если однажды компьютер победит обычного шахматиста или чемпиона мира по шахматам, это будет проявлением эволюции ИИ.

Если помните, Алан Тьюринг в 1952 году создал первую компьютерную программу для игры в шахматы, и это было великим достижением, но ещё более значимым было то, что тогда ещё не было никаких компьютеров. Это был просто алгоритм, который он использовал, чтобы играть в шахматы, и он действовал как человеческий компьютерный процессор. Важно помнить, что отцы-основатели компьютеров определили путь, по которому должен был развиваться ИИ, следуя процессам человеческого мышления. Противоположным путем является то, что мы называем атакой brute-force, или быстрым перебором возможных вариантов ходов.

Я ничего не слышал о соревнованиях с компьютерами в 1985 году, но на этой фотографии вы можете увидеть 32 доски, и хотя я играл с людьми, но на самом деле это была реальная игра против компьютеров. На то время было 4 ведущих производителя шахматных компьютеров, которые как раз представили их миру. Возможно, у кого-то из вас ещё сохранились такие компьютеры, сейчас это настоящие раритеты. У каждого производителя было по 8 компьютерных модулей, так что реально я играл с 32 противниками и выиграл все партии.

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

Итак, это был июнь 1985 года, а спустя 12 лет я сыграл против всего лишь одного компьютера. В 1997 году был матч-реванш, потому что я выиграл первый матч, который состоялся в 1996 году в Филадельфии. Я проиграл этот матч-реванш, но отмечу ради справедливости, переломный момент в компьютерных шахматах состоялся не в 1997, а в 1996 году, когда я выиграл матч, но проиграл первую партию. Затем я выиграл 3 партии, и счёт стал 4:2 в мою пользу.

На самом деле, здесь важен факт, что компьютер в то время был способен стать чемпионом мира по шахматам, если бы играл в обычном шахматном турнире. Я не ожидал от IBM, что они смогут за год проделать такую серьезную техническую работу по усилению своего компьютера. Но самой большой моей ошибкой, за исключением резкого повышения курса акций IBM, которые через 2 недели после матча подскочили с нескольких пунктов до миллиарда долларов, была невозможность прочитать мелкий шрифт. Потому что одной из проблем 1996 года, с которой я столкнулся, играя с компьютером Deep Blue, было то, что для меня он являлся «черным ящиком». Я ничего не знал о сопернике, о том, как он думает, какую тактику использует. Обычно, когда ты готовишься к игре, то изучаешь противника, неважно, будет ли это шахматный матч или футбольный, и, наблюдая за манерой игры, изучаешь его стратегию. Но в отношении «манеры игры» Deep Blue не было никакой информации.

Я постарался быть умнее и заявил, что к следующему матчу у меня должен быть доступ к играм, сыгранным Deep Blue. Они ответили: «Конечно!», но при этом добавили мелким шрифтом:

«…только во время официальных соревнований».

И это при том, что Deep Blue не сыграл ни одной игры вне лабораторных стен. Так что в 1997 я играл против «черного ящика», и всё получилось противоположно событиям 1996 года – я выиграл первую партию, но проиграл матч.

К слову, где были вы, хакеры, 20 лет назад, когда так были мне нужны? Правда, когда я пробегаю взглядом по рядам присутствующих, то понимаю, что многие из вас, наверное, тогда ещё не родились.

Самой большой моей ошибкой было то, что я воспринимал матч с Deep Blue как великий научный и социальный эксперимент. Я думал, что он будет великим, потому что действительно найдёт ту область, где человеческую интуицию можно сравнить с «грубой силой» компьютерных вычислений. Однако Deep Blue со своей феноменальной скоростью вычислений порядка 2 миллионов шахматных позиций в секунду, что было совсем неплохо для 1997 года, был чем угодно, но только не искусственным интеллектом. Его игра не внесла никакого вклада в раскрытие тайны человеческого интеллекта.

Он был разумен не более, чем обычный будильник, однако мне не легче от того, что я проиграл будильнику стоимостью 10 миллионов долларов.

Я помню пресс-конференцию во время церемонии открытия матча, когда человек, возглавлявший проект IBM, сказал, что это ознаменует конец научных опытов и победу науки. Поскольку у нас была одна победа и один проигрыш, я хотел сыграть третий матч, чтобы выяснить, кто же все-таки сильнее, но они разобрали компьютер, видимо, чтобы убрать единственного беспристрастного свидетеля. Я пытался выяснить, что случилось с Deep Blue, но не смог это узнать. Позже я узнал, что он сделал новую карьеру и теперь готовит суши в одном из терминалов аэропорта имени Кеннеди.

Я люблю суши, но компьютер мне там не нужен. Итак, на этом моя история с компьютерными шахматами довольно быстро закончилась. Но те из вас, кто тоже играет в шахматы или другие игры, знают, насколько мы уязвимы по сравнению с компьютерами, потому что мы не настолько стабильны, беспристрастны и совершаем ошибки. Даже игроки высочайшего уровня делают ошибки, например, во время матча на звание чемпиона, где делается 50 или 45 ходов, неизбежна хотя бы одна крохотная ошибка. Если играют живые люди, она не имеет особого значения, но если вы делаете ошибку при игре с машиной, то возможно, что вы не проиграете, но и не выиграете, потому что машина сумеет избежать поражения.

В какой-то момент я понял, что это просто вопрос времени, потому что мы не можем достигнуть такого же уровня бдительности и точности, которая необходима для победы над компьютером, потому что машина необычайно стабильна в своих поступках. Годы спустя мы стали свидетелями того, что машины постоянно выигрывали матчи. Ещё раз повторюсь – это всё касается всего лишь игры в шахматы, которая очень уязвима к методу игры brute-forсe, когда компьютер с огромной скоростью перебирает множество вариантов ходов и выбирает самый оптимальный. Это не искусственный интеллект, поэтому люди совершают ошибку, когда говорят, что человек — шахматист был побежден искусственным интеллектом.

Позже я сыграл еще несколько матчей против компьютеров. Однажды я проанализировал эти игры, используя современные шахматные движки, и это был довольно болезненный опыт. Это было путешествие в прошлое, и я был вынужден признать, насколько слабо провел эти матчи, потому что мог пенять только на самого себя. Однако в то время компьютерный «демон» не был настолько силён, вы можете не верить, но бесплатное шахматное приложение на вашем мобильном устройстве на сегодня сильнее, чем был Deep Blue. Конечно, если у вас есть шахматный движок типа asmFish или Comodo и новейший ноутбук, эта система будет еще мощнее.
Когда я играл против Deep Blue, думаю, это была 5 игра, компьютер в эндшпиле поставил вечный шах, и все стали говорить, что это великая победа и что компьютер показал феноменальное качество игры. Но сегодня, с современным компьютером, это выглядит просто смешным. Весь наш матч можно сыграть за 30 секунд, максимум минуту в зависимости от производительности вашего ноутбука. В начале я сделал ошибку, потом попытался спасти игру, Deep Blue сделал несколько ответных ходов и выиграл. Таковы правила игры, и в этом нет ничего плохого.

В 2003 году я сыграл ещё 2 матча против компьютера X3D Frintz, они оба закончились вничью. Организаторы заставили меня надеть 3-D очки, потому что компьютер имел 3-х мерный интерфейс.

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

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

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

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

Следуя русской поговорке: «если не можешь победить – присоединяйся!», я назвал продвинутыми шахматами игру, когда один человек с компьютером сражается против другого человека с компьютером.

В 1998 году я играл с представителем шахматной элиты из Болгарии, и самое интересное то, что мы оба не смогли хорошо сыграть, потому что не смогли максимизировать эффект от совместной работы с компьютером. Я задался вопросом, почему два великих игрока не смогли извлечь пользу от сотрудничества с ИИ. Ответ пришел позже с введением так называемого фристайла с ограничением количества подсказок со стороны компьютера. Вы можете играть, подключившись к суперкомпьютеру через интернет, можете использовать собственный компьютер или много компьютеров. Я хочу заметить, что пара «человек-компьютер» всегда превзойдет любой суперкомпьютер. Причина очень проста – компьютер компенсирует нашу рассеянность, и мы оказываемся в хорошем положении, переключаясь на компьютер, потому что это исключает уязвимость, когда другой компьютер может воспользоваться нашей человеческой слабостью.
Но в этом нет ничего сенсационного. Сенсацией стало то, что победителями соревнования стали не игроки высшего класса, а относительно слабые шахматисты с обычными компьютерами, но зато сумевшие создать улучшенный процесс взаимодействия. Это трудно сформулировать, потому что оно звучит парадоксально: слабый игрок плюс обычный компьютер плюс улучшенный процесс превосходят сильного игрока с мощным компьютером, но слабым процессом взаимодействия. Интерфейс решает всё!

Интересно то, что вам совсем не нужен сильный игрок, не нужен Гарри Каспаров, для того, чтобы находясь на стороне машины, найти наилучший ход, и на это есть простой ответ. Если сегодня рассматривать относительно сильные стороны человека и компьютера, можно выйти за пределы шахмат, но давайте начнем все-таки с них, потому что в шахматах имеются числа. Итак, мой рекордный шахматный рейтинг составлял 2851 балл, пока я не проиграл Магнусу Карлсену, и в момент завершения моей шахматной карьеры он составлял 2812 баллов. На сегодня Магнус Карлсен возглавляет рейтинг выше 2800 баллов. Примерно 50 игроков имеют рейтинг между отметками 2700 и 2800 баллов. Это элита шахматного мира. В наши дни мощь компьютера находится в пределах 3200 баллов, а с учетом специализированного программного обеспечения его рейтинг может достичь 3300-3400 баллов.

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

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

Я не знаю точные цифры, предположим, 60-65% людей выберут доктора, а 85% будут за компьютер, но психологически, если вы хороший доктор, вы не сможете это принять. Если посмотреть на сегодняшний технический прогресс, то можно сказать, что компьютеры ставят правдивый диагноз в 80 – 85 — 90 % случаев, но 10% все равно остаются людям! А это может представлять собой огромную разницу, ведь когда при выстреле пуля отклоняется всего на 1 градус, то она может пролететь на расстоянии нескольких сотен метров от мишени. Вопрос касается того, способны ли мы направить в нужное русло всю мощь компьютерных вычислений.
Поэтому я до сих пор верю, что все страхи по поводу того, что машины вскоре заменят всех нас, и это станет концом света, Армагеддоном — всего лишь слухи. Потому что, как я сказал, это касается творческих способностей человека, и уникальность компьютерного интеллекта состоит в том, что он всего лишь усиливает наши творческие способности, высвобождает их и подсказывает, как использовать их наилучшим образом.

Иногда, чтобы найти ответ на вопрос, стоит отойти от мира науки и углубиться в мир искусства. Как-то я нашел отличный парадокс, изложенный великим художником Пабло Пикассо: «Компьютеры бесполезны. Единственное, что они могут – это давать ответы». Я думаю, что в этом заключается великая мудрость и эти слова звучат обнадеживающе, потому что машины все же дают ответы, и эти ответы исчерпывающие!

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

Однажды я посетил хеджевый фонд Bridgewater Associates, где собирался поговорить с Дейвом Феруччи, одним из разработчиков суперкомпьютера Watson IBM. Мы говорили о том, могут ли машины задавать вопросы, и Дэйв сказал: «Да, компьютеры могут задавать вопросы, но они не знают, какие из вопросов действительно имеют значение». Вот в чем заключается суть. Таким образом, мы всё еще в игре и у нас есть шанс двигаться дальше, потому что игра человека и компьютера еще не закончена.

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

На одной из фотографий изображен Демис Хассабис со своей самообучающейся нейронной сетью AlphaGo. На самом деле это, вероятно, первая машина, которую можно назвать прототипом искусственного интеллекта.

Как я уже сказал, Deep Blue – это перебор brute-force, Watson – возможно, переходное звено, но не ещё не ИИ. AlphaGo — это программа глубинного обучения, которая самосовершенствуется, находя соответствующие модели, играя в миллионы и миллионы игр.

Я могу сказать, что в случае AlphaGo мы впервые имеем дело с настоящим «черным ящиком». Потому что, например, если мы потратим сотню лет на изучение тысячи миль игровых логов Deep Blue, то в конце концов доберемся до оригинальной идеи, почему было принято именно это решение и сделан именно этот ход. Что же касается AlphaGo, я уверен, что даже сам Демис Хассабис не сможет сказать, чем версия 6 лучше версии 9, или наоборот, имея в виду решение, принятое этой машиной.

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

Как-то я выступал в штаб-квартире Google, и они организовали мне экскурсию по Google X. Эта было очень интересно, потому что данная компания уверенно движется в направлении создания ИИ, решая проблемы создания самоуправляемого автомобиля или автономных дронов, самостоятельно доставляющих грузы. Однако не меньшей проблемой, чем техническое обеспечение ИИ, является проблема регулирования его деятельности. Люди говорят о том, что ИИ может полностью заменить их, лишив работы. Однако давайте призовем на помощь историю человеческой цивилизации – подобное происходило сотни и тысячи лет!

24:35 мин

https://www.youtube.com/watch?v=fp7Pq7_tHsY

Конференция DEFCON 25. Гарри Каспаров. «Последняя битва мозга». Часть 2

Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас оформив заказ или порекомендовав знакомым, 30% скидка для пользователей Хабра на уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps от $20 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?

Let's block ads! (Why?)

[Перевод] Эволюция разработчиков: каких игр нам ждать в будущем

image

В своей предыдущей статье я представил общий обзор видеоигровой экосистемы. Теперь я бы хотел рассмотреть по отдельности каждую категорию игр, описать их свойства, смысл их инноваций в функциональности и особенностях, а также рассказать о лучших стартапах в каждой из категорий. В этой статье я буду говорить только о разработчиках игр. Эта категория доминирует в игровой индустрии. Они составляют почти 60% от всего финансирования игровых экосистем (7,1 миллиарда долларов) и количества созданных стартапов (447).

Разработчики игр


К категории разработчиков игр относятся студии и издатели, занимающиеся созданием, приобретением и распространением новых игр. Это одна из наиболее уникальных категорий во всей экосистеме стартапов из-за её соотношения успехов к провалам. Из более чем 447 изученных мной разработчиков игр около 23% ушли с рынка и около 10% закрылись.

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

  • Мобильная платформа становится самой важной для издания игр.
  • Большинство разработчиков игр создаёт игры free-to-play.
  • Монетизация каждой игры происходит благодаря рекламе или внутриигровым покупкам: скинам, бустерам или статусным товарам.
  • Кроме того, стандартным подходом стало создание игр одновременно для всех платформ (консолей, мобильных, телевизоров и VR).
  • Создание конкурентной многопользовательской экосистемы или введение призов — обязательное требование для стимуляции увлечённости игрой.
  • Похоже, что всё больше разработчиков всеми возможными способами пытается построить вокруг своих игр сообщества: чаты, мероприятия в реальной жизни, лиги и многое другое.
  • Для привлечения зрителей и игроков все разработчики должны находить подход к инфлюенсерам.
  • Создание собственной уникальной франшизы (интеллектуальной собственности) или использование уже имеющейся франшизы — ключ к построению успешной игры.

Функции


Как разработчики игр различаются по используемым для создания игр инструментам или платформам.

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

Разработчики находят новые платформы для игр. Для них это возможность захватить рынок, на котором пока нет никого другого. Примеры:

  • Звук: разработчики наподобие Drivetime или Sensible Object позволяют пользователям играть в аудиоигры-викторины с Alexa или во время управления автомобилем.
  • Умные часы: Everywear Games и Pocket Gems создают игры для умных часов Android и Apple.
  • Чат-приложения: Knock Knock создавала игры для Facebook messenger. Neptune работала с Kakao. Mini Program компании Tencent вызвала появление множества игр для WeChat. Mojiworks создаёт игры и для Messenger, и для WeChat. Похоже, это отличная категория для короткого казуального геймплея, которой должны уделить внимание локальные телекоммуникационные компании или компании, предоставляющие услуги CPaaS.
  • Интернет вещей: похоже, что всё чаще традиционные настольные игры или игрушки сливаются с видеоигрми. Workinman Interactive создаёт интерактивные игрушки для таких брендов, как Disney, Nickelodeon, Atari и Fisher-Price. Mighty Bear Games создала пульсомер, управляющий сложностью игр. Sensible Object создала уникальную игровое устройство, объединившее в себе Jenga и Pokemon.
  • Телевизор: Nazara заключила партнёрское соглашение с Amazon для переноса локализованных индийских игр на Fire TV. Похоже, что телевизоры становятся важной платформой для всё большего количества разработчиков. Замедлит ли это рост рынка консолей?
  • VR/AR: Niantic, Leaftail Labs, Snatch, Next Games, Placeholder и Shifu в основном используют мобильные телефоны для социальных, интерактивных и совместных AR-проектов. VR тоже является предпочтительной платформой для разработчиков, желающих расширить рамки своих франшиз. Например, Resolution Games перенесла Angry Birds в VR. Другие разработчики делают шаги вперёд для усовершенствования игрового процесса в AR/VR. Subdream создаёт собственное оборудование, которое можно использовать в VR-играх. Meleap создаёт собственную арену для AR-игр.
  • Тематические парки аттракционов: Immersive Game Labs и Survios построили крытый видеоигровой парк, в котором люди могут сыграть в их игры. Тематические парки с VR/AR какое-то время были в тренде, то теперь экономика управления ими немного нестабильна.

image

Почему это важно?

Новые платформы позволяют различными способами дотянуться до новых или уже опытных геймеров. Если стать пионером в издании игр на таких новых платформах, то это может определить развитие новой категории игр. Например, Mech Mocha утверждает, что 96% мобильных игроков раньше не играли в игры на PC/консолях. Новые платформы могут также наносить ущерб уже существующим платформам. Tencent в своём годовом отчёте упомянула, что её доходы от игр на PC падают и будут постепенно снижаться из-за перехода пользователей на мобильный гейминг.

Разработчики создают собственные игровые движки

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

  • От игровых движков к изданию: такие движки, как Unreal Engine компании Epic Games или Real World Platform компании Niantic являются примерами того, как разработчики создают успешные игры и делятся своей платформой с другими разработчиками. Разработчики наподобие The Ready Games издают игры, созданные на их платформе разработки; ещё основное преимущество заключается в том, что пользователям для разработки игр необязательно знать код. Workinman Interactive создаёт аппаратные симуляторы Интернета вещей.
  • Внутренний игровой движок: такие разработчики, как Super Evil Megacorp и Mojiworks создали собственные игровые движки для разработки своих мобильных и чат-игр, не намереваясь продавать на них лицензии. Похоже, что такой путь даёт студиям больше контроля над производительностью игр и скоростью их разработки. Dapper Labs воспользовалась немного иным подходом: она позволяет разработчикам использовать свой код для создания игр в пределах игровой экосистемы компании. Её цель — создание новых мини-игр на основе бренда Dapper Labs. Технологический стек компании FRVR помогает ей меньше чем за секунду загружать качественные игры на почти любой мобильный телефон.
  • Игровые инструменты: кроме того, многие разработчики также продают лицензии на инструменты, которые они используют для повышения производительности, масштабов распространения или увлекательности собственных игр. Teatime Games предлагает реализацию в играх трансляций и видеочата. Reload Games предлагает услуги внутриигровой музыкальной студии и инструменты для ускорения загрузки игр. Midas Touch создаёт ПО для 2D-анимаций.

Почему это важно?

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

Количество создаваемых игр

Похоже, что небольшая группа студий и издателей агрессивно устанавливает цели в производстве и приобретении новых игр. Возможно, причина этого в том, что они ищут подходящие франшизы, которые могут обеспечить студии большую отдачу. Некоторые издатели, например Games2win стимулируют к нулевой зависимости от отдельной игры. Hypixel, Mighty Bear и Flowplay пытаются создавать множество мини-игр в пределах одной успешной существующей игры. MZ Studios поставила перед собой цель выпуска новой игры через каждые 6 месяцев. The Ready Games стремится выпускать игру каждые 48 часов. Примеры приблизительного количества игр от разработчиков или издателей:


image

Почему это важно?

Создавать качественные игры быстро сложно. Phoenix Labs сообщает, что для создания её кооперативной игры про охоту free-to-play для PC необходимо больше 200 человек. При правильной реализации игры могут приносить сотни тысяч, если не миллионы долларов в день. Разработчики и издатели постоянно находятся в поисках нового большого хита. Игровые движки эволюционируют, создавать игры становится всё проще, поэтому нас должно быть ждёт потоп из всё большего количества контента.

Redemption Games сообщает: «Бизнес мобильных игр стал одной из самых конкурентных областей в мире. В магазинах приложений уже сотни тысяч игр, и чтобы добраться до вершины, требуется уникальная комбинация навыков и усилий, от дизайна игры, до маркетинга и службы поддержки. Нет никаких „серебряных пуль“ и возможностей срезать путь».

Сотрудничество студий

Разработка игры — это искусство, а художники постоянно сотрудничают. Существует группа разработчиков, сотрудничающая для получения опыта, обмена франшизами и помощи в региональном распространении. Очевидно, что многие сотрудничают с издателями для получения помощи в производстве и распространении. Другие разработчики, например Hutch, предпочитают издаваться самостоятельно. Тем не менее, слияние медиа, контента и игровых франшиз постоянно генерирует захватывающий новый геймплей. Примеры сотрудничества:

  • Halfbrick Studios работает с Mech Mocha над локализацией и повторным выпуском их игр в Индии.
  • Workinman сотрудничает с Addicting Games для создания напряжённой боевой игры, отражающей дух серии Man at Arms.
  • Digit Game Studio объединила усилия с Scopely для создания игры Star Trek Fleet Command на основе голливудской франшизы.

Особенности


Слияние медиа, брендов, известных лиц с играми

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

  • Известные личности в играх: почти все известные медийные личности из телешоу, фильмов или сами актёры использовались или будут использоваться в играх. Примером тому служат Niantic, использующая Гарри Поттера; Jam City, использующая Family Guy и Marvel; Second Dinner, тоже использующая Marvel; Scopely, использующая Walking Dead и Wheel of Fortune; nWay с Power Rangers; MZ Games с Final Fantasy; Moonfrog Labs, использующая самые кассовые индийские фильмы и самых популярных актёров; Funtactix создаёт игры на основе фильмов-блокбастеров. Neptune заключила партнёрское соглашение с платформой обмена сообщениями Kakao и использует её персонажей для создания игр. HQ Trivia применяет другой подход — она приглашает участвовать в своих играх таких знаменитостей, как Дуэйн Джонсон, Роберт де Ниро, Гордон Рамзи, Нил Патрик Харрис и Алисия Сильверстоун. Действительно уникальным примером создания игр на основе популярных медиа является Hypixel. Эта компания начинала с создания собственных забавных видео на Youtube. Youtube-канал привлёк достаточно внимания, что помогло компании создать собственные мини-игры Minecraft на основе её видеороликов.
  • От игр к медиа: для дальнейшего развития игровых франшиз разработчики создают на основе своих игр медиа. Они могут быть простыми, например Kixeye создаёт видео и блоги о том, как проходить её игры. Или они могут зайти так далеко, как Niantic, создающая на основе своей игры Ingress телешоу. Youxigu участвовала в финансировании производства двух кинофильмов и экшн-фильмов. Moshi Monster выпускает книги, журналы, игрушки, коллекционные карты, музыкальные альбомы, фильм и даже коврики для собак.
  • От брендов к играм: разработчики также объединяются для создания игр с знаменитыми брендами. Например, Playstudios заключила партнёрское соглашение казино в Вегасе для предоставления вознаграждений. The Ready Games сотрудничает с самыми популярными брендами. Animoca Brands создавала игры для Mattel. 704Games создала шесть игр, посвящённых NASCAR.
  • От игр к играм: разработчики часто видоизменяют существующие популярные настольные/аркадные игры. Mech Mocha создала видеоигру о популярной в Индии настольной игре под названием Ludo. Subdream изготовила VR-игру на основе популярной в 1980-х аркадной игре Galaga. Jackpocket позволяет играть в государственные лотереи на телефоне. Scopely создала игры на основе Yahtzee. SuperSolid создаёт проекты на основе Sims. Этот список можно продолжать.

Почему это важно?

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

Game Ownership

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

  • Dapper Labs открыла свой код, чтобы позволить разработчикам создавать игры на основе игровых франшиз.
  • Epic Games и Funcom раздают моды, чтобы игроки могли создавать внутри популярных игр собственные миры.
  • Следующая игра Mythical Games будет сильно зависеть от генерируемого пользователями контента; игроки и инфлюенсеры смогут обмениваться созданными цифровыми ресурсами.
  • Klang Games позволяет игрокам создавать множество персонажей и управлять ими. Персонажи продолжают функционировать, даже когда игрок выходит из игры.
  • Pocket Gems позволяет пользователям создавать собственную сюжетную линию в игре, чтобы делиться ею с другими игроками.
  • IMVU создала собственный модный блог для создаваемых игроками внутриигровых стилей. Их аватаров могут признавать топ-моделями и демонстрировать на баннере игры.

Почему это важно?

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

Мероприятия, турниры и соревнования

Ещё одна нарастающая тенденция среди разработчиков и издателей — повышение вовлечённости в игру проведением соревнований. Это может быть реализовано внутри игры или в реальной жизни. Такие мероприятия помогают разработчикам управлять вовлечённостью и новыми стратегиями монетизации. Вот несколько примеров:

  • Niantic проводит мероприятия и местные встречи для своих AR-игроков. Некоторые такие встречи являются фундаментальной частью геймплея. Кроме того, компания проводит конкурсы для разработчиков.
  • В годовом отчёте Tencent говорится, что она может повысить вовлечённость пользователей благодаря киберспортивным мероприятиям и прямым трансляциям.
  • Nazara Technologies получила многолетние лицензионные права на организацию и проведение соревнований ESL в Индии.
  • Funplus и Millennial Esports организуют киберспортивные мероприятия и лиги. У Millennial Esports даже есть собственная игровая арена в Лас-Вегасе.
  • Такие игры, как The Ready Games и HQ Trivia, ежедневно проводят внутриигровые соревнования с призами.

Почему это важно?

Киберспорт — это очень быстрорастущее движение. Разработка кооперативных и соревновательных игр становится обязательным требованием. Участие в индустрии киберспорта обязательно для разработчиков.

image

Социальная сторона

Во все виды игр добавляются социальные компоненты. Это может быть всё, что угодно: чат, прямые трансляции или VR-миры. Добавление интерактивных социальных компонентов постепенно становится для разработчиков неизбежным. Примеры:

  • Mech Mocha сосредоточена на создании в своих играх социальных компонентов. Их DAU (Daily Active Users) в среднем проводят во внутриигровом голосовом чате по 25 минут.
  • Teatime Games предоставляет возможность трансляции видео в своих гоночных играх с боями один на один.
  • Мобильное приложение Funplus позволяет пользователям стримить прохождение игры и общаться со зрителями.
  • Flowplay создала виртуальный мир, позволяющий игрокам общаться и вместе играть в игры.

Почему это важно?

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

Примеры использования


В этом разделе мы рассмотрим виды целевых аудиторий, на которых сосредоточены разработчики игр и расскажем о том, как эволюционируют их компании.

Демографическое таргетирование

Стоит упомянуть небольшую группу игровых разработчиков, нацеленную на определённые демографические группы. Вот примеры распространённого демографического таргетирования:

  • Географическое: Mech Mocha считает, что существует недостаток игр для отдельных регионов. Компания сосредоточена на завоевании аудитории в маленьких областях Индии. Games2Win тоже заявляет, что сосредоточена на создании локализованного контента.
  • Гендерное: Singularity 6 надеется, что основной частью аудитории её будущей игры будут женщины. Nix Hydra сосредоточена на создании ориентированных на женщин игр. Gram Games создала движение под названием Project 22%, обслуживающее женскую аудиторию.
  • Соревновательное: Gamelynx создаёт командные соревновательные игры для мобильных устройств, благодаря чему киберспорт становится более доступным и глобальным.
  • Профессиональное: Level Ex создаёт видеоигры для врачей, передающие сложности медицинской практики. Обучающая система в виртуальной реальности компании Radd3 помогает игрокам в американский футбол морально подготовиться к будущим играм благодаря их визуализации. Кроме того, она позволяет игрокам тренироваться без риска травм.

Почему это важно?

Обслуживание узкой целевой аудитории позволяет разработчикам открывать новые направления для роста. Например, Nazara Technologies сообщает: «Имея рынок в 500 миллионов игроков, Индия имеет потенциал для создания собственной League Of Legends».

Предоставление полномочий инфлюенсерам

Инфлюенсеры — важнейший компонент маркетинговой стратегии разработчиков игр. Phoenix Labs замечает: «реальность такова, что большинство игроков пришли в Dauntless потому, что в неё кто-то играл в Twitch или на YouTube, или же подавляющее большинство людей приходит, потому что играют их друзья и они хотят играть с ними». Способ общения разработчиков игр с инфлюенсерами критически важен для направления трафика к их новым проектам. Примеры инновационных методов, которые издатели используют удовлетворения потребностей инфлюенсеров:

  • Funcom представляет инфлюенсерам эксклюзивные индивидуально созданные комплекты, позволяющие им создавать качественный контент для зрителей.
  • Программа Support-A-Creator компании Epic Games позволяет творцам контента зарабатывать деньги на Fortnite и других играх из Epic games store.
  • Seriously обрела успех благодаря разработке серии кампаний с YouTube-инфлюенсерами на основе благотворительных инициатив и организовала их так, чтобы они совпали со временем выхода обновлений игр.
  • Proletariat создаёт полномасштабные системы и инструменты стриминга, позволяющие зрителям общаться с любимыми стримерами прямо внутри игр.

Почему это важно?

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

Эволюция игровых стартапов

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

  • Рост приобретаемых портфолио: многие успешные разработчики игр начинают приобретать другие студии или инвестировать в них ради развития. В частности, этим занимаются Jam City, Scopely и Tencent.
  • Из разработчиков в издатели: многие разработчики используют собственные игровые движки или охват аудитории для построения своего портфолио издаваемых игр. Например, Epic Games использует свой игровой движок как средство роста в роли издателя. Paradox Interactive тоже создаёт цифровую платформу распространения. Rumble Games предлагает разработчикам инструменты для издания и работы в своём игровом сервисе.
  • Из разработчиков в поставщики услуг: Workinman Interactive создаёт дизайн, IoT-игрушки, арт, выставки и предоставляет другие услуги брендам, стремящимся разрабатывать игры. ZGames предлагает услуги разработки игровых дизайн-документов, создания артов, прототипирования и исследования аудитории дял выпуска в магазине приложений, а также пострелизную настройку параметров на основе аналитики и серверную поддержку. Virtuos также предоставляет широкий спектр игровых услуг и обучение для игровых художников.
  • От разработчика к продуктам: Mind Candy создаёт успешную интеллектуальную собственность, разросшуюся на книги, продукты для домашних животных, приложения для домашних животных, коврики для кормления, коллекционные карты, журналы, игрушки, музыкальные альбомы и фильмы.

Почему это важно?

Создание легендарных игр — практически невозможная задача. Поэтому разработчикам постоянно нужно искать новые способы эволюционировать, расти и монетизироваться, иначе они неизбежно потерпят крах. В идеале разработчики должны продолжать выпускать новые игры, но всегда иметь в запасе план Б.

Лучшие разработчики игр, за которыми стоит наблюдать

Hypixel Studio, Immersive Games, Niantic, Jam City, Second Dinners Studios, Mech Mocha, Mythical Games, Everywear Games, BigBox VR, Embark Studios, Drivetime, Dapper Labs, Subdream Studio, Jackpocket, Epic Games, Phoenix Labs, Leaftail Labs, GAMEE, Singularity 6, 1939 Games, 704Games, Neptune, Knock Knock, Scopely, Jumpship, FRVR, Klang Games, Mighty Bear Games, Mightier, Sensible Object, Redemption Games, Gamelynx, Teatime Games, KIXEYE, Digit Game Studio, Level Ex, Volley, HQTrivia, Trailmix, Caret Games, nWay, Manitcore Games, Mind Candy, Snatch, Mojiworks, 3rd Eye Studios, Supersolid, The Ready Games, PLAYSTUDIOS, Super Evil Mega Corp, Portalarium, Pocket Gems, Seasun, Next Games, Armada Interactive, Hutch, PlaySimple Games, Bonfire Studios, Mino Games, Seriously, Ministry of Games, Machine Zone, Supreme Games, Beyond Games, Moonfrog Labs, Telltale Games, Proletariat, Derby Games, Kingnet, Playdots, cloudcade, Flaregames, Octro, Nix Hydra, Thatgamecompany, Funplus, Cocone, Tabtale, Chukong Technologies, Youxigu, Grand Cru, FlowPlay, Games2Win, Arkadium, Peak Games, Reloaded Games, MindSnacks, Red Robot Labs, Dang Le, SNSplus и ещё некоторые другие.

Заключение


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

Let's block ads! (Why?)