Русский
Русский
English
Статистика
Реклама

Предсказание

Перевод Жизнь в 2030

21.08.2020 20:17:07 | Автор: admin

Француз Фабрис Гринда всегда любил рисковать он успешно вложился в сотни компаний: Alibaba, Airbnb, BlaBlaCar, Uber и даже русский аналог Booking сервис Oktogo. У него особое чутьё на тренды, на то, каким может быть будущее.


Месье Гринда не только инвестировал в чужие бизнесы, но и создавал свои. Например, онлайн-доска объявлений OLX, которой пользуются сотни миллионов человек, его детище.


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


Несколько лет назад он дал интервью журналу Alliancy, обсуждая мир в 2030 году.



Журнал Alliancy: Какие серьезные изменения вы видите через 10 лет?


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


Автомобили станут общими. На сегодняшний день беспилотные автомобили уже проехали безаварийно миллионы миль. Но если обычный автомобиль в Штатах в среднем стоит менее 20.000 долларов, то система, позволяющая превратить его в автопилотируемый, стоит порядка 100.000. Если смотреть со стороны финансов общее применение все еще невозможно. Также отсутствует правовая база, так как нужно определиться с тем, кто будет нести ответственность в случае аварии.


А что насчет рентабельности?


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


Но когда затраты на водителя исчезнут, когда автомобили станут автономными, основным расходом станет амортизация в течение нескольких лет. Общий автомобиль, используемый 90% времени, станет намного дешевле таким образом на всех уровнях владение автомобилем больше не будет иметь смысла. Предприятия будут покупать парки автомобилей, а затем предоставлять их другим предприятиям, которые будут заниматься их эксплуатацией, как Uber, с достаточно плотным графиком, так что автомобиль будет доступен через пару-тройку минут, в том числе и в менее плотно населенных районах. Это особенно сильно изменит общество, поскольку в США основной источник занятости вождение автомобиля. Освободится очень много рабочих рук, стоимость вождения снизится.


Случилась ли революция в области коммуникаций?


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


В 2030 мы будем работать где захотим, когда захотим и столько, сколько захотим.

Чего же мы ждем?


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


У нас появится своего рода улучшенная телепатия, мы будем обмениваться информацией мысленно: я думаю текст, отправляю его вам, вы читаете его на сетчатке глаз или на контактных линзах. Нам больше не будет нужно носимое устройство с мелким экраном и с постоянно наклоненной к нему головой, которое отвлекает нас и ограничивает поле зрения. Но и через 10 лет это будет только начало. Лазеры, умеющие отправлять изображения на сетчатку, существуют, но линзы все еще низкого качества. Чтение мыслей пока еще приблизительное и требует суперкомпьютера с 128 электродами. В 2030 году эквивалент такого суперкомпьютера будет стоить 50 долларов. На доработку достаточно малых и эффективных электродов, а также соответствующих программ, возможно потребуется 20-25 лет. Однако смартфоны исчезнут неизбежно.


А что с медициной?


Сегодня пять врачей могут поставить пять разных диагнозов одной и той же болезни, поскольку люди не настолько хороши в диагностике. Так, Watson, суперкомпьютер от IBM, лучше врачей определяет некоторые виды рака. В этом есть логика, поскольку он учитывает каждый микрон результатов МРТ или рентгеновского снимка, а врач смотрит не более пары минут. Через 5 лет диагностика достанется только компьютерам, через 10 мы получим универсальный диагностический аппарат для всех распространенных болезней, включая простуду, ВИЧ и прочих.


Примерно в это же время революция произойдет и в хирургии. Робот-доктор Da Vinci уже провел пять миллионов операций. Хирургия и далее будет становиться всё более роботизированной или автоматизированной, что позволит сократить разрыв производительности между хирургами. Впервые начнет снижаться стоимость лекарств. Кроме того вся бумажная работа и административная неэффективность уйдут после внедрения электронных медицинских карт. Через 10 лет мы получим диагностику с постоянной обратной связью о том, что нам стоит делать с точки зрения питания, лекарств, при все более эффективной хирургии и гораздо более низкой стоимости затрат на медицину.


Еще одна революция образование?


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


N.B. от редактора: Представляю, как бы удивился Сократ, если бы увидел, как проходят наши интенсивы. Если офлайн-интенсивы до пандемии коронавируса ещё кое-как походили на классическое образование (лекционный конференц-зал, спикеры-учителя, студенты за столами, вместо глиняных дощечек или папируса ноутбуки и планшеты, вместо майевтики или сократовской иронии Докер или продвинутый курс по Kubernetes c практическими кейсами), которое особо не менялось в инструментах с античной эпохи, то лекции через Zoom, курилка и общение в Telegram, презентации и видео-записи занятий в личном кабинете Определённо, Сократ этого бы не понял. Так что будущее уже наступило а мы и не заметили. И пандемия коронавируса подтолкнула нас к изменениям.

Как это изменит наши возможности?


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


А что с начальной и средней школами?


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


Что-то еще?


Наибольший прорыв будет в непрерывном образовании. Массово меняются требования, в продажах несколько лет назад важно было знать, как оптимизировать вашу видимость в поисковых системах (SEO). Сегодня нужно понимать оптимизацию магазина приложений (ASO). Как это знать? Пройти курсы на сайтах, к примеру Udemy, лидера в этой области. Они создаются пользователями, а затем доступны всем по цене от 1 до 10 долларов...


N.B. от редактора: Вот честно, лично я не уверен, что курсы, созданные пользователями, а не практиками, такая уж хорошая идея. Мир сейчас заполонили тревел- и бьюти-блогеры. Если дополнительно заполонят учителя-блогеры, то будет трудно найти по-настоящему полезный и профессиональный материал в куче контента. Я хорошо знаю, сколько труда десятков людей нужно, чтобы создать по-настоящему полезный курс по тому же мониторингу и логированию инфраструктуры в Kubernetes, основанный не на мануалах и статьях, а на практике и опробованных кейсах. Ну, и на встреченных граблях куда уж без них в работе и освоении нового инструментария.

Проще говоря мир работающих обязательно изменится?


Миллениалы (рожденные позже 2000 года) терпеть не могут работу с 9 до 18, работу на начальника, самого начальника. В настоящее время мы видим бурный рост предпринимательства в США, усиленный доступностью ряда сервисных приложений по запросу. Половина рабочих мест, созданных после кризиса 2008 года, это люди, работающие сами на себя, либо те, кто работают на Uber, Postmates (доставка еды на дом), Instacart (доставка еды от соседей).


Это персонифицированные услуги, доступные по запросу...


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


Станем ли мы счастливее в 2030?


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


Значит не будет социального неравенства?


Идут разговоры о расширении неравенства, а в действительности происходит сближение социальных классов. В 1900 году богатые люди уходили в отпуск, но не бедные. Сегодня один летит на частном самолете, другой на EasyJet, но оба садятся в самолет и уходят в отпуск. 99% американских бедняков имеют воду и электричество, а 70% из них владеют автомобилем. Если смотреть на такие факторы, как младенческая смертность и ожидаемая продолжительность жизни неравенство сокращается.


А что насчет изменения климата и стоимости энергии, могут они повлиять на эти достижения?


Этот вопрос будет решен без регулирования и вмешательства государства. Мы собираемся перейти к безугольной экономике, но по чисто экономическим причинам. Один мегаватт солнечной энергии стоит уже меньше доллара, если сравнить с 100 долларами в 1975 году. Это получилось в результате улучшения производственных процессов и производительности. Также достигнуто равенство стоимости солнечной энергии в некоторых регионах, где создание электростанций дорого обходится. В 2025 году стоимость солнечного киловатта будет меньше, чем стоимость угольного киловатта без субсидий. Как только это произойдет, в процесс будут вложены десятки миллиардов долларов. В 2030 начнется ускоренное внедрение солнечной энергии. Стоимость мегаватта станет намного ниже, что в свою очередь снизит затраты на многие другие вещи и улучшит качество жизни. Я настроен весьма оптимистично.


Подробнее..

Немного об ускорении программы распараллеливание (ручное или автоматическое) на базе сверхоптимистичных вычислений

18.08.2020 20:07:52 | Автор: admin
Здравствуйте, уважаемые читатели. В этой публикации речь пойдет о такой (уже ставшей привычной) вещи как ускорение работы программы путем применения параллельных вычислений. Технологии организации таких вычислений известны это и обычное многопоточное программирование, и применение специальных интерфейсов: OpenMP, OpenAcc, MPI, DVM и многих других (при этом распараллеливаются циклы, используется векторизация или конвейеризация, организуются ленивые вычисления, выделяются независимые блоки программы, которые можно запустить в параллель и т.п.).

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

Идея распараллеливания


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

for (int i = 0; i < N; i++) {x = f(y);y = g(x);}

На первый взгляд, распараллелить такой цикл невозможно. Однако мы попробуем. Попытаемся исполнять параллельно первый и второй операторы тела цикла. Проблема состоит в том, что на момент вычисления g(x) должен быть известен x, но он будет рассчитан только в конце первой части. Что же, введем некоторую схему, которая в начале второй части попытается предсказать новое значение x. Можно это сделать, например, с помощью линейной предикции, которая обучится предсказывать новое значение x, опираясь на историю его изменения. Тогда вторую часть можно считать параллельно с первой (это и есть сверхоптимизм), а когда обе будут подсчитаны, сравнить предсказанное значение x с реальным, полученным в конце первой части. Если они примерно равны, то результат вычислений обеих частей можно принять (и перейти к следующему витку цикла). А если они сильно отличаются, то потребуется пересчитать только вторую часть. При такой схеме в какой-то части случаев получим чистое распараллеливание, в остальных фактический последовательный счет. Алгоритм выполнения цикла при этом такой:

for (int i = 0; i < N; i++) {Распараллеливаем на два ядра {На ядре 1  считаем x = f(y). Далее передаем во вторую часть получение значение x;На ядре 2  предсказываем значение x* и считаем y* = g(x*). Получаем значение x из первой части и сравниваем его с x*. Если разница невелика, то y = y* и завершаем итерацию цикла. Если различие большое, повторяем вычисление с новыми данными: y = g(x). }}

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

Реализация распараллеливания сверхоптимистичные вычисления


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

for (int i = 0; i < N; i++) {Распараллеливаем на два ядра, включаем частично транзакционную память {Ядро 1 (транзакция 1):x = f(y);Предсказывающий_Канал.put(x);Ядро 2 (транзакция 2):Предсказывающий_Канал.get(x);y = g(x);}}

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

Некоторые полезные применения: нейронные сети, метод частиц в ячейках


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

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

Автоматизация распараллеливания C-программ


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

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

Исходная программа:


#include <stdlib.h>#include <stdio.h>#include <math.h>#pragma auto parallelize#pragma auto pure(malloc,fabs,free,sizeof,omp_get_wtime)#define theta 1.83#define NX 40#define NY 40#define h 0.1#define NP 15000// Собирающая электростатическая линза#define U1 200#define U2 5000#define e -1.5E-13#define m 1E-11#define e0 8.85E-12#define V (h*h)#define tau 0.000015#define T 0.09#define POISSON_EPS 0.01#define TOL_EPS 0.25int main() {        double * U  = (double *)malloc(NY*NX*sizeof(double));        double * UU = (double *)malloc(NY*NX*sizeof(double));        double * EX = (double *)malloc(NY*NX*sizeof(double));        double * EY = (double *)malloc(NY*NX*sizeof(double));double * PX = (double *)malloc(NP*sizeof(double));double * PY = (double *)malloc(NP*sizeof(double));int * X = (int *)malloc(NP*sizeof(int));int * Y = (int *)malloc(NP*sizeof(int));double ro[NY][NX];split_private double t;split_private double tm;split_private int i, j;for (i = 0; i < NY; i++)for (j = 0; j < NX; j++) {UU[i*NX+j] = j == NX-1 ? U2 : j == NX/2 && (i < NY/4 || i > 3*NY/4) ? U1 : 0.0;EX[i*NX+j] = 0.0;EY[i*NX+j] = 0.0;}for (i = 0; i < NP; i++) {int x, y;PX[i] = 0.5*NX*h*rand()/RAND_MAX;PY[i] = NY*h*rand()/RAND_MAX;x = PX[i]/h;y = PY[i]/h;if (x < 0) x = 0;else if (x > NX-1) x = NX-1;if (y < 0) y = 0;else if (y > NY-1) y = NY-1;X[i] = x;Y[i] = y;}tm = omp_get_wtime();for (t = 0.0; t < T; t += tau) {unsigned int n[NY][NX] = { 0 };double err;int ptr = 0;for (i = 0; i < NY; i++)    for (j = 0; j < NX; j++, ptr++)U[ptr] = UU[ptr];for (i = 1; i < NY - 1; i++)for (j = 1; j < NX - 1; j++) {EX[i*NX+j] = -(U[i*NX+j+1]-U[i*NX+j-1])/2.0/h;EY[i*NX+j] = -(U[(i+1)*NX+j]-U[(i-1)*NX+j])/2.0/h;}for (i = 0; i < NP; i++) {PX[i] += tau*e*EX[Y[i]*NX+X[i]]/m;PY[i] += tau*e*EY[Y[i]*NX+X[i]]/m;}for (i = 0; i < NP; i++) {int x = PX[i]/h;int y = PY[i]/h;if (x < 0) x = 0;else if (x > NX-1) x = NX-1;if (y < 0) y = 0;else if (y > NY-1) y = NY-1;Y[i] = y;X[i] = x;n[y][x]++;}for (i = 0; i < NY; i++)for (j = 0; j < NX; j++)ro[i][j] = n[i][j]*e/V;do {err = 0.0;for (i = 1; i < NY - 1; i++)for (j = 1+(i-1)%2; j < NX - 1; j+=2) {  int ptr = i*NX + j;  if (!(j == NX/2 && (i < NY/4 || i > 3*NY/4))) {double _new = (1-theta)*UU[ptr] + theta/4.0*(UU[ptr-1]+UU[ptr+1]+UU[ptr+NX]+UU[ptr-NX]-h*h*ro[i][j]/e0);double loc_err = fabs(UU[ptr] - _new);if (loc_err > err) err = loc_err;UU[ptr] = _new;  }}for (i = 1; i < NY - 1; i++)for (j = 1+i%2; j < NX - 1; j+=2) {  int ptr = i*NX + j;  if (!(j == NX/2 && (i < NY/4 || i > 3*NY/4))) {double _new = (1-theta)*UU[ptr] + theta/4.0*(UU[ptr-1]+UU[ptr+1]+UU[ptr+NX]+UU[ptr-NX]-h*h*ro[i][j]/e0);double loc_err = fabs(UU[ptr] - _new);if (loc_err > err) err = loc_err;UU[ptr] = _new;  }}for (j = 0; j < NX; j++) {UU[j] = UU[NX + j];UU[(NY-1)*NX + j] = UU[(NY-2)*NX + j];}} while (err > POISSON_EPS);}for (i = 0; i < NY; i++) {for (j = 0; j < NX; j++)printf("%lf\t", UU[i*NX+j]);printf("\n");}return 0;}

Автоматически распараллеленная программа


#include "transact.h"#define split_private /* split-private */#include <stdlib.h>#include <stdio.h>#include <math.h>#define theta 1.83#define NX 40#define NY 40#define h 0.1#define NP 15000#define U1 200#define U2 5000#define e -1.5E-13#define m 1E-11#define e0 8.85E-12#define V (h*h)#define tau 0.000015#define T 0.09#define POISSON_EPS 0.01#define TOL_EPS 0.25int  main(  ){  double * U  = (double *)malloc(NY*NX*sizeof(double));  double * UU = (double *)malloc(NY*NX*sizeof(double));  double * EX = (double *)malloc(NY*NX*sizeof(double));  double * EY = (double *)malloc(NY*NX*sizeof(double));  double * PX = (double *)malloc(NP*sizeof(double));  double * PY = (double *)malloc(NP*sizeof(double));  int * X = (int *)malloc(NP*sizeof(int));  int * Y = (int *)malloc(NP*sizeof(int));  double ro[NY][NX];  split_private double t;  split_private double tm;  split_private int i, j;  for ( i = 0; i < NY; i++ )    for ( j = 0; j < NX; j++ )      {        UU[i*NX+j] = j == NX-1 ? U2 : j == NX/2 && (i < NY/4 || i > 3*NY/4) ? U1 : 0.0;        EX[i*NX+j] = 0.0;        EY[i*NX+j] = 0.0;      }  for ( i = 0; i < NP; i++ )    {      int x, y;      PX[i] = 0.5*NX*h*rand()/RAND_MAX;      PY[i] = NY*h*rand()/RAND_MAX;      x = PX[i]/h;      y = PY[i]/h;      if ( x < 0 )        x = 0;      else        if ( x > NX-1 )          x = NX-1;      if ( y < 0 )        y = 0;      else        if ( y > NY-1 )          y = NY-1;      X[i] = x;      Y[i] = y;    }  tm = omp_get_wtime();#pragma omp parallel num_threads(2) private(t,tm,i,j)   {    int __id__ = omp_get_thread_num();    TOut<double > * out_ro = __id__ == 0 ? new TOut<double >("ro63", (NY)*(NX), 2, 0.01, -1, "63") : NULL;    TIn<double > * in_ro = __id__ == 1 ? new TIn<double >("ro63", (NY)*(NX), 2, 0.01, -1, "63") : NULL;    for ( t = 0.0; t < T; t += tau )      {        unsigned int n[NY][NX] = { 0 };        double err;        int ptr = 0;        if ( __id__ == 0 )          {            for ( i = 0; i < NY; i++ )              for ( j = 0; j < NX; j++, ptr++ )                U[ptr] = UU[ptr];          }transaction_atomic("63")        {          if ( __id__ == 0 )            {              for ( i = 1; i < NY - 1; i++ )                for ( j = 1; j < NX - 1; j++ )                  {                    EX[i*NX+j] = -(U[i*NX+j+1]-U[i*NX+j-1])/2.0/h;                    EY[i*NX+j] = -(U[(i+1)*NX+j]-U[(i-1)*NX+j])/2.0/h;                  }              for ( i = 0; i < NP; i++ )                {                  PX[i] += tau*e*EX[Y[i]*NX+X[i]]/m;                  PY[i] += tau*e*EY[Y[i]*NX+X[i]]/m;                }              for ( i = 0; i < NP; i++ )                {                  int x = PX[i]/h;                  int y = PY[i]/h;                  if ( x < 0 )                    x = 0;                  else                    if ( x > NX-1 )                      x = NX-1;                  if ( y < 0 )                    y = 0;                  else                    if ( y > NY-1 )                      y = NY-1;                  Y[i] = y;                  X[i] = x;                  n[y][x]++;                }              for ( i = 0; i < NY; i++ )                for ( j = 0; j < NX; j++ )                  ro[i][j] = n[i][j]*e/V;              out_ro->put((double  *)ro);            }          else            {              double  ro[NY][NX];              in_ro->get((double  *)ro, 0);              do                {                  err = 0.0;                  for ( i = 1; i < NY - 1; i++ )                    for ( j = 1+(i-1)%2; j < NX - 1; j+=2 )                      {                        int ptr = i*NX + j;                        if ( !(j == NX/2 && (i < NY/4 || i > 3*NY/4)) )                          {                            double _new = (1-theta)*UU[ptr] + theta/4.0*(UU[ptr-1]+UU[ptr+1]+UU[ptr+NX]+UU[ptr-NX]-h*h*ro[i][j]/e0);                            double loc_err = fabs(UU[ptr] - _new);                            if ( loc_err > err )                              err = loc_err;                            UU[ptr] = _new;                          }                      }                  for ( i = 1; i < NY - 1; i++ )                    for ( j = 1+i%2; j < NX - 1; j+=2 )                      {                        int ptr = i*NX + j;                        if ( !(j == NX/2 && (i < NY/4 || i > 3*NY/4)) )                          {                            double _new = (1-theta)*UU[ptr] + theta/4.0*(UU[ptr-1]+UU[ptr+1]+UU[ptr+NX]+UU[ptr-NX]-h*h*ro[i][j]/e0);                            double loc_err = fabs(UU[ptr] - _new);                            if ( loc_err > err )                              err = loc_err;                            UU[ptr] = _new;                          }                      }                  for ( j = 0; j < NX; j++ )                    {                      UU[j] = UU[NX + j];                      UU[(NY-1)*NX + j] = UU[(NY-2)*NX + j];                    }                }              while ( err > POISSON_EPS )                ;            }        }      }    delete in_ro;    delete out_ro;  }  for ( i = 0; i < NY; i++ )    {      for ( j = 0; j < NX; j++ )        printf("%lf\t", UU[i*NX+j]);      printf("\n");    }  return 0;}

Итоги


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

Python, корреляция и регрессия часть 4

19.05.2021 12:19:31 | Автор: admin

Предыдущий пост см. здесь.

Предсказание

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

9-кратный олимпийский чемпион по плаванию Марк Шпитц завоевал 7 золотых медалей на Олимпийских играх 1972 г. Он родился в 1950 г. и, согласно веб-страницы Википедии, имеет рост 183 см. и вес 73 кг. Посмотрим, что наша модель предсказывает в отношении его веса.

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

Матрица содержит коэффициенты для каждого из этих признаков:

Предсказанием модели будет сумма произведений коэффициентов и признаков xв каждой строке:

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

Напомним, что размерность итоговой матрицы будет числом строк из первой матрицы и числом столбцов из второй матрицы:

Здесь Tx это произведение матрицы размера 1 nи матрицы размера n 1. Результатом является матрица размера 1 1:

Исходный код вычислений очень прост:

def predict(coefs, x):     '''функция предсказания'''    return np.matmul(coefs, x.values) 
def ex_3_29():    '''Вычисление ожидаемого веса спортсмена'''    df = swimmer_data()    df['бин_Пол'] = df['Пол'].map({'М': 1, 'Ж': 0}).astype(int)     df['Год рождения'] = df['Дата рождения'].map(str_to_year)    X = df[['Рост, см', 'бин_Пол', 'Год рождения']]     X.insert(0, 'константа', 1.0)    y = df['Вес'].apply(np.log)     beta = linear_model(X, y)    xspitz = pd.Series([1.0, 183, 1, 1950]) # параметры Марка Шпитца    return np.exp( predict(beta, xspitz) )  
84.20713139038605

Этот пример вернет число 84.21, которое соответствует ожидаемому весу 84.21 кг. Это намного тяжелее зарегистрированного веса Марка Шпитца 73 кг. Наша модель, похоже, не сработала как надо.

Интервал уверенности для конкретного предсказания

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

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

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

Здесь yp это предсказание, плюс или минус интервал. Мы пользуемся t-распределением, где степень свободы равна n - p, т.е. размер выборки минус число параметров. Это та же самая формула, которая ранее применялась при вычислении F-тестов. Хотя указанная формула, возможно, пугает своей сложностью, она относительно прямолинейно транслируется в исходный код, показанный в следующем ниже примере, который вычисляет 95%-ый интервал предсказания.

def prediction_interval(x, y, xp):    '''Вычисление интервала предсказания'''    xtx    = np.matmul(x.T, np.asarray(x))    xtxi   = np.linalg.inv(xtx)      xty    = np.matmul(x.T, np.asarray(y))     coefs  = linear_model(x, y)     fitted = np.matmul(x, coefs)    resid  = y - fitted    rss    = resid.dot(resid)      n      = y.shape[0]  # строки    p      = x.shape[1]  # столбцы    dfe    = n - p     mse    = rss / dfe    se_y   = np.matmul(np.matmul(xp.T, xtxi), xp)    t_stat = np.sqrt(mse * (1 + se_y))         # t-статистика    intl   = stats.t.ppf(0.975, dfe) * t_stat       yp     = np.matmul(coefs.T, xp)    return np.array([yp - intl, yp + intl])

Поскольку t-статистика параметризуется степенью свободы ошибки, она принимает в расчет присутствующую в модели неопределенность.

Если вместо интервала предсказания потребуется рассчитать интервал уверенности для среднего значения, мы попросту можем опустить прибавление единицы к se_y при вычислении t-статистики t_stat.

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

В приведенном выше графике модель тренируется на выборке из 5 элементов и показывает, как 95%-й интервал предсказания увеличивается по мере нашего движения дальше от среднего роста. Применив приведенную выше формулу к Марку Шпитцу, в результате получим следующее:

def ex_3_30():    '''Интервал предсказания       применительно к данным о Марке Шпитце'''    df = swimmer_data()    df['бин_Пол'] = df['Пол'].map({'М': 1, 'Ж': 0}).astype(int)     df['Год рождения'] = df['Дата рождения'].map(str_to_year)    X = df[['Рост, см', 'бин_Пол', 'Год рождения']]     X.insert(0, 'константа', 1.0)    y = df['Вес'].apply(np.log)     xspitz = pd.Series([1.0, 183, 1, 1950])  # данные М.Шпитца    return np.exp( prediction_interval(X, y, xspitz) )
array([72.74964444, 97.46908087])

Этот пример возвращает диапазон между 72.7 и 97.4 кг., который как раз включает в себя вес Марка 73 кг., поэтому наше предсказание находится в пределах 95%-ого интервала предсказания. Правда оно лежит неудобно близко к границам диапазона.

Границы действия модели

Марк Шпитц родился в 1950 г., за несколько десятилетий до рождения самых возрастных пловцов на Олимпийских играх 2012 г. Пытаясь предсказать вес Марка, используя его год рождения, мы виноваты в том, что пытаемся экстраполировать слишком далеко за пределы наших тренировочных данных. Мы превысили границы действия нашей модели.

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

Согласно данным, в 1972 г. 22-летний Марк Шпитц имел рост 185 см. и весил 79 кг.

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

Следует отбирать признаки не только, опираясь на их предсказательную силу, но и на их актуальность для моделируемой области.

Окончательная модель

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

Модель произведет приблизительно с такими значениями:

Наши признаки для Марка на играх 1972 г. таковы:

Эти признаки можно использовать для предсказания его соревновательного веса при помощи приведенного ниже примера:

def ex_3_32():    '''Окончательная модель для предсказания        соревновательного веса'''    df = swimmer_data()    df['бин_Пол'] = df['Пол'].map({'М': 1, 'Ж': 0}).astype(int)     X = df[['Рост, см', 'бин_Пол', 'Возраст']]     X.insert(0, 'константа', 1.0)    y = df['Вес'].apply(np.log)     beta = linear_model(X, y)    # предсказать вес Марка Шпитца    xspitz = pd.Series([1.0, 185, 1, 22])     return np.exp( predict(beta, xspitz) )
78.46882772630318

Пример возвращает число 78.47, т.е. предсказывает вес 78.47 кг. Теперь результат находится очень близко к истинному соревновательному весу Марка, равному 79 кг.

Примеры исходного кода для этого поста находятся в моемрепона Github. Все исходные данные взяты врепозиторииавтора книги.

Резюме

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

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

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru