python

Нейрокурятник часть 2: про бота, который постит фотографии

  • пятница, 19 мая 2017 г. в 03:15:39
https://habrahabr.ru/post/328940/
  • Обработка изображений
  • Машинное обучение
  • Python
  • Open source
  • Data Mining


image

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

Статьи про нейрокурятник

Заголовок спойлера
  1. Вступление про обучение себя нейросетям
  2. Железо, софт и конфиг для наблюдения за курами
  3. Бот, который постит события из жизни кур — без нейросети
  4. Разметка датасетов
  5. Параллельное участие в соревнованиях, визуализации внутренностей нейросетей, развитие архитектур моделей
  6. Работающая модель для распознавания кур в курятнике


Мама, мессенджер, бот, куры


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


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


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


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


/home/sshuser/.virtualenvs/cv/bin/python3 /home/sshuser/chickencoop/pi_surveillance_mod2.py --conf /home/sshuser/chickencoop/conf.json </dev/null &>/dev/null &

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


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


Чтобы сделать такого бота в Telegram, вам нужно:


  1. Создать свой канал
  2. Создать бота в телеграм при помощи BotFather (это тоже бот в телеграме), вам понадобится токен бота для того, чтобы постить сообщения и фотографии.
  3. Сделать скрипт для бота и демонизировать его.

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


Для отслеживания события создания файла я использую bash-скрипт, события слушает inotify-tools. Скрипт отправки вызывается не сразу, а после 10-ти секундного ожидания. Сделано это потому, что файл загружается еще некоторое время после создания, а с учетом прекрасной скорости интернета в курятнике, опытным путем установлено, что 10 секунд — самое оно.


#!/bin/sh
DIR="/your/directory"
inotifywait -m -r -e create --format '%w%f' "$DIR" | while read f

do
	PARDIR="$(dirname $f)"
	PARFOLD="$(basename $PARDIR)"
	FBASENAME="$(basename $f)"
	FILEEXT="${FBASENAME##*.}"
	EXT="jpg"
	FOLD="resized"
	if [ $FILEEXT = $EXT ]; then
		if [ $PARFOLD = $FOLD ]; then
			# sleep til file is uploaded
			sleep 10
			python3 /your/directory/bot_request.py --params /your/directory/params_public.json -f $f
		fi
	fi

done

bot_request.py:


import requests
import json
import datetime
import argparse
import warnings

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--params", required=True,
        help="params json. chat, token")
ap.add_argument("-f", "--file", required=True,
        help="file path")
args = vars(ap.parse_args())

# filter warnings, load the configuration and check if we are going to use server
warnings.filterwarnings("ignore")
params = json.load(open(args["params"]))

# set url and post data
payload = {"chat_id": params["chat"],
	"caption": "motion detected {ts}".format(ts=datetime.datetime.now().strftime("%A-%d-%B-%Y-%I:%M:%S%p"))}
url = "https://api.telegram.org/bot" + params["token"] + "/sendPhoto"
files = {'photo': open(args["file"], "rb")}

# post request
request = requests.post(url, files=files, data=payload)

# log the output
with open("/path/to/your/botlogs/{dt}-{chat}.txt".format(dt=datetime.datetime.now().strftime("%d-%B-%Y"), chat=params["type"]), "a") as logfile:
    logfile.write("\n" + request.text)

params_public.json:


{
	"chat": "@your_chat",
	"token": "your_tocken",
	"type": "public"
}

Вот, собственно, и все, максимально простое и работающее решение готово.


image

Честно и правдиво: почему я так часто считаю себя тупым/тупой

Немного болтовни. Кто-то сочтет за нытье — go ahead and do whatever you want. Главный посыл этой части статьи — если кто-то критикует вас, не предлагая в ответ хотя бы направления, в котором надо искать ответ, не расстраивайтесь. Нет, делать прототипы и решать задачи, получать опыт можно и без знания всего и вся. Человек не может знать все. Я не верю, что есть люди, которые не ошибаются, и которым знания спускаются в виде откровений с небес.


imageУж не знаю, кто им там нашептывает истины...

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


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


Поэтому, когда я пишу код, мне всегда очень не хочется выкладывать его в паблик. Потому что я знаю, что я сделала что-то неправильно, не по канону. И, самое важное, я всегда знаю, что будет критика. Найдется хотя бы один человек, который знает, как нужно сделать, но он не предложит решение, не даст никакого ключа к пониманию, он просто скажет что-то из разряда «У вас все неправильно, все не работает, вы никчемный человек (а я Д'Артаньян, но я не скажу, почему, и не предложу ничего взамен вашей коряво написанной статье, потому что не хочу)».


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


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


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


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


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


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


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