All streams
Search
Write a publication
Pull to refresh
346
Коробов Михаил @kmikeread⁠-⁠only

Пользователь

Send message
А в перловых правилах вероятности вручную подбирались, или как-то еще?
Еще IPython в профилировании помогает: там есть встроенные %prun, %%prun, %timeit и %%timeit, которые позволяют запускать cProfile и timeit над выражениями/ячейками. Если line_profiler и memory_profiler установить, то еще %lprun и %mprun добавляются. Очень удобно использовать с ipython notebook.

Из статистических профайлеров еще есть yappi, использовал его несколько лет назад; сейчас глянул в репозиторий — меньше суток назад последний коммит)
Непонятно только, как Pony ORM использовать с такой лицензией — она же требует открывать код сайта, который Pony ORM использует. Это ведь даже не GPL, а AGPL. Или я где-то что-то упускаю?
В репозитории есть 2 части: GUI для аннотации и собственно модель. Мне кажется, что их хорошо бы разделить. Т.к. GUI для аннотации — штука интересная, а с моделью все довольно непроработано. Например, нет скриптов для оценки качества. Добавлять какие-то дополнительные feature-функции, смотреть, как работают нынешние, настраивать параметры модели и т.д. толку поэтому мало сейчас.

В функции тренировки непонятно, зачем score вычислять на тех же данных, на которых тренировка идет (это неправильно и даже вредно). Ну т.е. можно надеяться, что «random forest не оверфиттится», но это не так, тем более когда используется бустинг.

Еще было бы хорошо использовать соглашения scikit-learn. Например, обычный порядок «X, y» в функции тренировки, FeatureUnion и DictVectorizer для вычисления фич — вместо своих классов.

Картинка, кстати, неправильная — границы, по которым разделяются данные в random forest, не так выглядят :)
Хорошая тема, и на русском почти ничего нет — пишите еще!
В Numenta/NuPIC смущает то, что там все как будто «в своем мире» живет. Я в нейросетях ни разу не эксперт, но смущает, что у них на сайте/в доках/инструкциях нигде нет сравнения с «традиционными» нейросетевыми моделями и другими статистическими методами. В whitepaper вместо того, чтоб сравнивать с другими методами машинного обучения, все сравнивается с нейронами человеческого мозга — ну куда это годится. И терминология вся какая-то непонятная. Ну, например «Swarming» вместо «cross-validation + hyperparameter optimization». Как будто все писали биологи, которые понятия не имеют о статистике и машинном обучении. Или как будто старались впечатлить не-экспертов. И ссылки все только на работы основателя фирмы. Это очень все подозрительно. Короче говоря, выглядят они научными фриками. Вполне возможно, что я не прав, и в этом всем на самом деле что-то есть (тем более что в нейросетях я мало что понимаю), но подача все-же странная какая-то.
Вот это в Python 2.x почти всегда неправильно (то, что используется Python 2.x, можно понять из синтаксиса print):

print 'выход из блока'

Если unicode_literals не импортированы сверху файла, то 'выход из блока' тут — это байтовая строка, которая закодирована в ту кодировку, в которой хранится исходный код.

print байтовые строки выводит «как есть», никак не преобразуя — просто передает байты на выход. Поэтому если кодировка, которую использует консоль, не совпадает с кодировкой исходного кода, то консоль будет декодирует байты неправильно, и получим мусор на выходе. С ascii текстом это обычно не проблема, т.к. большинство кодировок кодирую ascii одинаково, но тут есть не-ascii символы. Для того, чтобы print использовал кодировку консоли, нужно печатать юникодные строки:

print u'выход из блока'

В этом случае Python перед тем, как передать строку на выход, закодирует ее именно в кодировку консоли. Там не все так просто (иногда кодировку консоли сложно определить), но все же печать юникодных строк гораздо надежнее.

Тут еще может смутить то, что если код набрать в интерпретаторе (REPL), то обычно print 'выход из блока' работает, т.к. константа берется из консоли, а sys.stdin.encoding обычно совпадает с sys.stdout.encoding. А если потом код сохранить в py файл, то все может сломаться, т.к. кодировка файла вполне может не совпадать с кодировкой консоли.
График, кстати, не нравится.

1. Если график по годам, то что это за плавная линия такая?
2. Текущий год еще не закончился, а 2006, возможно, начался для хабра не с января, так что «горб» не дает правильной картины.
Ну так и в 680mx все то же самое, кроме частоты и 2 гигов памяти вместо 4. В статье 780M с 680M сравнивают, 680M и 680MX — это разные вещи, в imac-ах 680mx были.
Это же вроде ровно то же самое, что и 680MX из предыдущего топового imac, который год назад вышел. Разве что памяти 4GB и незначительно частоту подняли.
Насчет повторного обхода и разделения парсинга/загрузки — можно просто кэш включить. Правила кеширования там вполне гибко настраиваются — если стандартные не устраивают, можно свой «policy» написать. Стандартные — dummy и RFC2616: github.com/scrapy/scrapy/blob/master/scrapy/contrib/httpcache.py

Для рестарта там есть doc.scrapy.org/en/latest/topics/jobs.html — правда, сам не пользовался. См. также github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py. Мы у себя кастомную мидлварь используем, которая очередь запросов в HBase держит.

Добавление полей не приведет к ликвидации собранных данных, т.к. данные по дефолту никуда не сохраняются :) В scrapy есть возможность настраивать, куда и как данные сохранять (с помощью Item Exporters или мидлвари), и есть несколько дефолтных способов экспорта (json, csv, xml). Мы у себя все автоматом в HBase складываем (раньше монга была), + внутренняя админка к этому. Ну как внутренняя, за деньги клиенты на этой всей инфраструктуре своих спайдеров могут запускать.

C Item'ами удобно — понятно, какой на выходе будет json или csv, например. Если нужны совсем неструктурированные данные (на самом деле это большая редкость), то создать Item c полем data, да и все. Или совсем их не использовать — никто не мешает в обработчике делать с извлеченными данными что угодно, сохранять их в базу, например, или сразу в csv файл дописывать.

Чтоб парсить jsvascript, мы с одним из авторов Scrapy делаем велосипед: github.com/scrapinghub/splash. Это сервис на PyQT4 / webkit / twisted, который к scrapy никак не привязан, но позволяет через HTTP API выполнять js на сайтах, получать результаты вычислений, получать html и делать скриншоты. Подход немного не такой, как в phantomjs и т.д.; иногда может быть удобнее, иногда нет; вроде должно работать быстрее — можно считать, что на каждый запрос к сервису вкладка браузера открывается, все параллелится средствами webkit.

У Scrapy, как мне кажется, есть одна довольно серьезная проблема — это туториал. Там все очень запутанно, и не с той стороны объясняется: ни слова про метод start_requests, например. Это в рамках туториала на этом PyCon US поправится, скорее всего.
bugs.python.org/issue1338264 — вот issue 2005 года про это, для Python 2.4, закрыт как wont fix :) Цитата:

Space for integer objects in particular lives in an immortal free list of unbounded size… If you don't want that, don't do that ;-)
Легко :)

# примеры для Python 2.7
def create_temp_strings():
    temp_value = [str(x) for x in xrange(10000000)]  
    
def create_temp_ints():
    temp_value = [x*2 for x in xrange(10000000)]

Если вызвать функцию create_temp_strings(), то она в пике займет мегабайт 700 памяти, но после завершения потребление памяти вернется к прежнему уровню. Если вызвать create_temp_ints(), то под Python 2.7 она займет в пике мегабайт 250, и они так и останутся занятыми после ее завершения. И там, и там используется xrange; разница в том, что в create_temp_strings() инты не находятся в памяти одновременно, а перебираются по одному. То, что все строки находятся в памяти одновременно, к проблеме не ведет, т.к. для строк объем преаллокации ограничен.

См., например, примечания к docs.python.org/2/library/gc.html#gc.collect и deeplearning.net/software/theano/tutorial/python-memory-management.html#internal-memory-management

Я, может, неправильно это все «free lists» называю — там для чисел вроде списки пулов, а не просто списки. Но это уже детали.
А точно нужно было в памяти всё сразу держать? Часто можно код организовывать так, чтоб это не требовалось. В Python для этого всякие плюшки есть — генераторы, модуль itertools. Значительно удобнее, чем на C :) Занимало бы тогда мегабайт 50 вместо 2 гигабайт.
С целыми числами не все так просто, кстати :) В CPython есть так называемые «free lists» — куски памяти, выделяемые под объекты заранее, чтоб не вызывать malloc по многу раз. Есть отдельные free lists для различных встроенных типов (словарей, кортежей, чисел и т.д.)

Так вот, если для словарей и кортежей размер free list ограничен (1000 что-ли объектов), то в Python 2.x размер free list для чисел не ограничен. Это означает, что если в памяти в какой-то момент одновременно находится миллион разных целых чисел (экземпляров int), то они останутся там навсегда (до завершения процесса). Сборщик мусора этим всем не занимается, т.к. к сборке мусора это все отношения не имеет. Пробежались по xrange(1000000) — все ок, пробежались по range(1000000) — миллион объектов int остался в памяти навсегда.

В одной из 3.х версий это как-то обошли.

Ну и, понятное дело, если важно, сколько миллион чисел занимает, то его лучше хранить в array.array (или numpy.ndarray), чтоб не создавать ненужные объекты int и убрать оверхед на все эти указатели.
Там в примере 11 большая разница между list и id / type: функция list создает проблемы пользователю библиотеки (т.к. она перекрывает list в области видимости модуля), а параметры id/type — нет, т.к. они перекрывают id/type только в области видимости функции (эта область видимости пользователю явным образом не доступна). Пользователю нужно называть аргументы функции id/type при вызове, но это не ведет ни к какому перекрытию, т.к. это, по сути, просто создание словаря с ключами 'id' и 'type'.

Такие названия аргументов могут создать проблемы разработчику функции, но это менее серьезная проблема, т.к. id и type используются очень редко (и часто неправильно, вместо is и isinstance), да и ошибку в короткой функции заметить проще. Но это нужно иметь в виду, да.

Схожая проблема:

class Foo(object):
    id = 'foo'
    id_upper = id.upper()

    def foo(self, x):
        return id(x)

Тут builtin «id» перекрывается, но только на время, пока создается класс (выполняется его тело); после создания класса (например, после импорта) перекрытия уже нет: id теперь доступен как атрибут Foo, т.е. опять это, по сути, ключ в словаре, который в пользовательском коде «намусорить» не может (ну разве что пользователь locals/globals обновит сам). Строка «return id(x)» во время создания класса не выполняется, так что функция Foo.foo вызывает builtin.
В питоне 3.3 есть довольно похожая штука, ExitStack называется.

Пример из статьи примерно так можно записать:

from contextlib import ExitStack

with ExitStack() as stack:
    f = stack.enter_context(open('file.txt', 'w))  # <- интеграция с другими контекст-менеджерами
    stack.callback(print, "Defer called")  # <- обычный коллбэк
    
    @stack.callback   # <- так тоже можно добавить коллбэк
    def my_defer():
        recover()
        
    print("Ok )")
    raise Exception("WTF?")

    print("Never printed (((") 

Из плюсов — стандартность, отсутствие хаков с inspect.stack в реализации, отсутствие необходимости привязывать все к функции целиком (контекст можно задать через with), возможность передавать stack как параметр куда угодно.

См. docs.python.org/3/library/contextlib.html#contextlib.ExitStack и www.wefearchange.org/2013/05/resource-management-in-python-33-or.html

UPD: под 2.х можно поставить contextlib2.readthedocs.org/en/latest/
Похоже, сортировка требуется как раз из-за способа кодирования автомата: он хранится одним куском памяти, без указателей («double array»), и поэтому удаление оттуда требует перемещения большого количества данных. Видимо, с упорядоченными входными данными можно инкрементально строить автомат без необходимости удалять оттуда что-либо — или хотя бы локализовать изменения, сообразить сейчас не могу.
Если правильно понял статью и комментарий, то штука, похожая на «дельта кодирование переходов», есть в реализации DAFSA code.google.com/p/dawgdic/. Конкретно в dawgdic есть ограничение на общее количество переходов (из-за 32битных чисел везде), так что гугл-н-граммы туда засунуть не получится. Но для морфологии работает отлично.
Большинство систем морфологии создавались в бородатые времена, когда память имела больше значения. При этом скорость морфологического анализа для многих реальных задач узким местом не является: особого смысла во всех этих миллионах разборов/сек нет, когда большинство алгоритмов синтаксического анализа — O(N^3) от длины предложения. Мне кажется, из-за этого такая любовь к префиксным деревьям.

Насчет размера: насколько знаю, способа закодировать DAFSA (иногда aka DAWG) как «succinct data structure» пока не придумали (с сохранением хотя бы асимптотики всех операций), а для задач морфологии получается, что DAFSA занимает меньше памяти, чем всяческие succinct trie, так что уменьшить размер не получается.

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

Использование хэшей немного смещает баланс «скорость <-> память» в сторону скорости (особенно если не нужны «хитрые» операции). Получается выигрыш раз в 10 по памяти и проигрыш раза в 2-4 по скорости. Но скорости и так хватает за глаза (у меня выходило в среднем 1500ns для получения всех разборов слова из DAFSA, с учетом обертки на Python), а реализации и там, и там достаточно простые, особенно если готовые библиотеки использовать. Видимо, поэтому DAFSA используют чаще.

Information

Rating
Does not participate
Location
Екатеринбург, Свердловская обл., Россия
Works in
Date of birth
Registered
Activity