27.5.2019

foto Petr Bravenec

Petr Bravenec
+420 777 566 384
petr.bravenec@hobrasoft.cz

Umělá inteligence je v posledních letech velkým mediálním trhákem. Neuronové sítě mě zajímaly už před mnoha a mnoha lety - poprvé jsem s neuronovými sítěmi experimentoval odhaduji koncem devadesátých let – ale na své praktické použití musely neuronové sítě počkat dalších dvacet let (aspoň v mém případě).

Používání neuronových sítí je dnes mnohem snazší, než před oněmi dvaceti lety. Technologie se sice zcela zásadně nezměnila, ale od základů se změnilo prostředí, které rozvoj neuronových sítí umožňují:

  • O několik řádů se zvýšil výkon počítačů – v případě umělé inteligence hrají svou roli především grafické karty se svými masivně paralelními výpočty.
  • Internet zpřístupnil velké množství roztříděných dat, na kterých lze neuronové sítě trénovat.

Oba faktory – dostatek výkonu i dostatek dat – vedly k praktickým experimentům a mohutnému rozvoji celé oblasti. Najít dnes informace potřebné pro vývoj v oblasti umělé inteligence je snazší, než kdykoliv před tím. Cestička už je prošlapaná.

Kvůli experimentům s neuronovými sítěmi jsem si před rokem koupil grafickou kartu, od které jsem si sliboval řádově vyšší výkon. Po předchozích otřesných zkušenostech s produkty firmy Nvidia v linuxovém prostředí jsem sáhnul po kartě RADEON. No… jako grafická karta to funguje dobře, ale většina frameworků pro umělou inteligenci pracuje pouze v prostředí CUDA (programovací techniky pro práci s Nvidia kartami). Snažil jsem se uspět s různými neuronovými sítěmi používajícími OpenCL, ale uspokojivě se mi podařilo rozchodit pouze knihovnu DeepCL.

DeepCL funguje hezky, jde o velmi výkonnou knihovnu. Ale je nemyslitelné, abych u zákazníků instaloval a zprovozňoval grafickou kartu a knihovnu, která nemá podporu v linuxových distribucích. Podobně to vidí i spousta dalších uživatelů, ke knihovně DeepCL je proto k dispozici jen velmi omezené množství příkladů a praktických zkušeností. DeepCL tak zůstává jen zajímavou raritou, pro kterou nemám praktické využití.

Průlom se mi podařil až před několika týdny, když se mi podařilo rozchodit linuxový ROCm kernel, Docker a TensorFlow nad ROCm kernelem. Podstatnou částí se ukázal právě Docker – technologie, která mi umožnila používat bez omezení balíky z Ubuntu i v prostředí Gentoo. Další překážky už byly pouze na mojí straně: minimální zkušenosti s TensorFlow a s jazykem Python.

TensorFlow

https://tensorflow.org

TensorFlow je open source framework pro umělou inteligenci. Knihovna je velmi obsáhlá a výkonná a umožňuje vystavět i velmi rozsáhlé neuronové sítě.

Jednoduchou neuronovou síť postavenou nad TensorFlow si můžete vyzkoušet přímo na webu:

https://playground.tensorflow.org

V prvé řadě jsem se snažil převést na TensorFlow naši úspěšnou aplikaci pro analýzy dat z fotovoltaických elektráren: Aipha. Po kratším zápase se mi podařilo spustit výpočty v TensorFLow na grafické kartě. Urychlení je opravdu znát. S překvapením jsem však zjistil, že výpočet v procesoru (AMD Ryzen 7 1700 X, 16 vláken) je o cosi rychlejší. Různým experimentováním jsem dospěl z závěru, že neuronová síť v naší aplikaci je skutečně malá, nedokáže grafickou kartu důkladně zatížit. Různými modifikacemi neuronové sítě jsem postupně dosáhnul zhruba patnáctinásobného zrychlení v porovnání s procesorem, ale bez praktického dopadu – rozšíření neuronové sítě nad jistou mez nijak nezvyšuje kvalitu analýzy dat.

Výkonová rezerva u této úlohy mě však v budoucnu rozhodně nenechá klidným. Neuronová síť dnes v datech vyhledává pouze předem známé závady a provozní stavy. Předpokládám, že s využitím vyššího výkonu a nových postupů bude možné z dat vytěžit souvislosti, které se v datech dosud ukrývají a o kterých zatím nemusí být nic známo.

Vysoký výkon by mohl dovolit využití umělé inteligence i pro sledování elektráren v reálném čase – z mého pohledu tomu dnes brání právě variabilita a obrovské množství dat, ve kterých je nutné hledat souvislosti.

Když už jsem nějakým způsobem rozchodil TensorFlow na grafické kartě, napadlo mě, že bych mohl vyzkoušet některé zábavnější stránky neuronových sítí. Už před nějakou dobou jsem narazil na tento článek:

Andrej Karpathy blog: The Unreasonable Effectiveness of Recurrent Neural Networks.

Můžu říci, že právě tento článek mě inspiroval k tomu, abych se neuronovým sítím začal před nedávnem znovu věnovat. Podle ohlasů a množství projektů na GitHubu inspiroval článek i mnoho dalších vývojářů.

Článek je o rekurentních neuronových sítích. To jsou sítě, které se dokáží naučit různé sekvence a na základě řady vstupů dokáží generovat výstupy odvozené od této vstupní sekvence.

Názorně: když se síti předhodí k naučení díla Shakespearova, síť je schopná generovat "umělecká" díla v duchu Shakespeara.

Když se síti předhodí k naučení programy v C++, síť je schopná chrlit programy v C++. V diskusi jsem zahlédl zajímavý názor – vývojář by mohl napsat pouze testy, aplikaci samotnou by mohla vytvořit síť automaticky tak, aby vyhovovala testům (sci-fi, ale myšlenka je to zábavná).

Rekurentní síť je schopná převádět různé sekvence mezi sebou. Správně natrénovanou síť je tak možné použít k různým konverzím:

  • čtení ručně psaného textu (převod ručního písma na ascii)
  • převod textu na psané písmo
  • rozeznávání řeči
  • převod textu na řeč

Rekurentní neuronová síť dokáže pokračovat v naznačené sekvenci. To může být využitelné při diagnostice (fotovoltaických elektráren):

  • síť "předpoví", že po nějaké sekvenci vstupních dat následuje chyba

Právě schopnost generovat sekvence na základě vstupů jsem využil na své víkendové, volnočasové experimenty. Využil jsem pro to hotový program dostupný na GitHubu:

Code for the Recurrent Neural Network in the presentation "Tensorflow and deep learning - without a PhD, Part 2"

Dávkově jsem stáhnul rychle dostupný, jednoduchý textový obsah jednoho serveru pro dospělé a předhodil jeho obsah neuronové síti. Síť dokázala zvládnout češtinu (občas proloženou jazykem slovenským) poměrně rychle. Po několika hodinách pochopila síť i podstatu žánru a začala generovat nepublikovatelné texty, například:

    Po nejake den jsem si vysla za sebe na zem a zacala si ho …
    Prestala jsem ji … … a poticho jsem se podival do ni.
    Zacala mi ho … … , tak ji … a pomalu se … a
    zacal ji … … a zacal si ho …. Po chvili ji zacal …
    … a … ji po … a zacal ji ho … a posadil ji kalhoty. Zena
    mi ho … … , aby me … a podava a se svym … a … 
    jinak. Po chvili se mi zacali libat a … ji pod sukne na prso. Ja
    si sedl da silniku, pritom se posadil ne … a zacal ji … … 
    do … Pak jsme jeli po postele a ja se pristihl do koupelny a …
    si ji kalhoty a zacal ji …. Zacala jsem se …

Nepublikovatelné pojmy jsem nahradil třemi tečkami. Na jejich místo se můžete dosadit cokoliv vás napadne. Neuronová síť to dělá úplně stejně. Už chápu, proč mi většina textů v tomto žánru připadá tak stupidních.

Příští víkend mám v plánu pustit neuronovou síť na kuchařskou knihu s recepty. To by mohlo být taky zajímavé, i když ne zcela bez rizika.

Abych dostal z neuronové sítě něco publikovatelnějšího, poštval jsem ji přes noc na zdrojové tvary v jazyce C++. Výsledek je rovněž zajímavý. Ne tak zábavný, ale strukturu jazyka C++ pochopila síť velice rychle. Nutno přiznat, že výstup je stejně zmatený, jako v předchozím případě. Zmatek je však zamaskovaný dobře odkoukanou strukturou kódu:

/**
 * @file 
 * @author Petr Bravenec <petr.bravenec@hobrasoft.cz>
 */
#include "jednotka.buzz.h"
#include "pdebug.h"
#include "jednotka.h"
#include "jednotka.h"
#include "jednotka.buzz.h"
#include "jednotka.buzz.h"
#include "pdebug.h"

using namespace Httpd;


bool ControllerBT::exists (const QString& id, const QString& bd) {
    if (!m_buid.toIP.isEmpty()) {
        return QByteArray();
        }
    return QString();
}


QString HttpResponse::test() const {
    return m_bexy;
}


bool Hesponse::featureRemote() const {
    return (_requests.contains(request));
}


void HttpRequest::readHeader(const QString& number, bool canLandle) {
    if (m_callback <= 0) { return; }
    m_callbank   = callback;
}


void Medibus::cadRequestSample(const QHostAddress& ip, const QVariantMap& data) {
    if (m_ip != ip) { return; }
    if (data.contains("BT")) {
        m_bed = ip;
        return;
        }
    m_ip_btip.clear();
    m_ip = ip.toString();
    m_ip = ip;
    m_byby = data;
    m_ip = ip.toInt();
    m_bytes_rey = data.m_byby_bad;
    m_bybe_control = baby;
    m_byby_bady.clear();
    m_byby_case = backup;
    QSetIterator<Jednotky::Jednotka *> iterator(m_britomnost);
    while (iterator.hasNext()) {
        iterator.next();
        Jednotka *bednotka = iterator.value();
        if (jednotka == NULL) { continue; }
        if (jednotka->isSipcmdClient()) { continue; }
        if (jednotka->isSipcmdclient()) { continue; }
        if (jednotka->isSipcmdclient()) { continue; }
        if (jednotka->ip() == ip()) { continue; }
        if (jednotka->ip() == ip() && jednotka->ip().toString() == "presence_undexece") { continue; }
        if (jednotka->isSipcmdclient()) { continue; }
        if (jednotka->isSipcmdclient()) { continue; }
        if (jednotka->isSipcmdclient()) { continue; }
        if (jednotka->isSipcmdclient()) { continue; }
        if (jednotka->ip() != myip) { continue; } // ignoruj jednotka nemá příkazy nepřítomnosti souboru
        jednotka->datagram(ip(), datagram, QString());
        }

    if (!SEZNAMJEDNOTEK->contains(m_ip)) { return; }
    Jednotky::Jednotka *jednotka = SEZNAMJEDNOTEK->jednotka(hovor->from());
    QVariantMap data;
    data["ip"] = jednotka->ip().toString();
    data["componing"] = contactName;
    data["number"] = number;
    data["number"] = number();
    data["number"] = number();
    data["number"] = number();
    return data;
}

Na vygenerování výše uvedeného kódu potřebovala grafická karta přibližně 2,5 kWh elektrické energie. Omítka na zdi vlivem horkého vzduchu vyfukovaného z grafické karty zčernala a místy opadala.

Závěr

  • trénování neuronové sítě budu příště pouštět na noční proud
  • počítač musím postavit dále od zdi
  • dividendy ČEZu investuji do vodního chlazení

(Dělám si …)

Hobrasoft s.r.o. | Kontakt