Duben a květen byly velmi náročné měsíce a potřeboval jsem trošku vypnout. Tak jsem si naordinoval červen jako volnější měsíc. Žádné ToDo, žádné deadliny. Budu se věnovat tomu, co mi zrovna přijde pod ruku a na co budu mít chuť.
No a hned o dva dny později to byla myšlenka zlepšení rozpoznávání SPAMu v rámci SupportBoxu.
Během posledních dvou měsíců jsme měli více a více zákazníků, kteří hlásili, že se jim množí různé typy spamu. Zejména pak ty obrázkové, ale i textové. Problém dnešního spamu je ten, že jej SpamAssasin nedokáže dostatečně dobře odhalit, protože mají vše technicky správně nastaveno a jsou tedy velmi podobné klasickým newsletterům.
Druhou věcí, aby se to trošku zkomplikovalo je, že máme velmi širokou škálu zákazníků. Od jednotlivců, kteří si chtějí sjednotit svých 15 e-mailových adres pod jedno přihlášení. Po e-shopy, které mají zastoupení po celé Evropě a desítky zaměstnanců. Také odvětví jsou od sexshopů po hotely. Takže to, co je pro jednoho jasně nepřípustné a spamující, může být pro druhého e-mail od dodavatele. Do toho se nám mixují různé jazyky pro e-shopy, které mají více poboček atd.
To zní jako velmi zajímavý problém na vyřešení. Takže ideální projekt na odreagování. A také ideální projekt pro strojové učení. Pardon, abych byl dostatečně startupově buzzwordový, tak musím použít označení AI!
Protože máme většinu infrastruktury na AWS, začal jsem zjišťovat, zda na to nemá Amazon nějakou vhodnou službu. A hle, má. A jmenuje se Machine Learning. No kdo by to byl řekl?
Umí toho opravdu hodně. Rozpoznávat obraz, video, text, zvuk a mnoho dalšího. Mě zajímal samozřejmě ten text. Tak jsem začal koumat dále. Zjistil jsem, že to celé dokážu zprovoznit a otestovat bez jediného řádku kódu! WOW!
Jako první jsem vyexportoval z DB posledních 1.000 zpráv z mé schránky, kterou mám napojenu do SupportBoxu. Stačí na to pět sloupečků: ID zprávy, odesílatel, předmět, text zprávy a příznak, zda se jedná o SPAM, či nikoliv.
Z těchto dat se vytvoří jednoduché CSV (max. 10.000 řádků), které se uloží na S3. Spolu s ním se uloží tzv. schema, aby ML věděl, co CSV obsahuje a co s ním má udělat. To vypadá následovně:
Jako první krok je potřeba natrénovat ML, takže se mu zadá cesta na S3 k CSV, on si dohledá schema a už stačí jen stisknout tlačítko Verify.
V dalším kroku potom načte z CSV několik řádků na ukázku a ověření, že je vše OK. Já jsem zde hned viděl problém s kódováním, takže jsem musel upravit vstup.
V dalších 2 kroucích se určí ID záznamů a dle kterého sloupečku má vyhodnocovat, zda je to spam, či nikoliv. Tím máme vstupní data zajištěna.
Další krok je natrénování ML modelu. V základním nastavení vezme Amazon 70 % vstupních dat, na nich model natrénuje a na zbylých 30 % potom udělá test, zda vyhodnocuje správně.
Poté, co natrénuje (cca 5 minut) a udělá evaluaci (ověření, cca 3 minuty), dostaneme výsledný model, kde můžeme určit práh, kdy se jedná o spam a kdy nikoliv. AWS na to má takovéto krásné udělátko:
U spamfiltru je nesmírně důležité, aby měl co nejmenší (ideálně nulový) výskyt tzv. false positives, tedy výsledků, kdy jsou e-maily chybně označeny jako SPAM.
Na obrázku je viděd šedé hejbátko, kterým lze táhnout doprava a doleva a tím se mění hodnoty vpravo, do té doby, než najdeme ideální nastavení “prahu”, kdy máme co nejnižší (ideálně nulové) false positives a také co nejnižší chybovost. V případě tohoto modelu je to 0.82.
A máme hotovo! Toto mi zabralo cca 2h, než jsem načetl dokumentaci, získal data pro natrénování modelu, poladil kódování, natrénoval a nastavil model.
Dalším krokem pro mě bylo ověřit, že takto natrenovaný stroj dokáže spolehlivě spam odhalovat. Na to má ML udělátko, které nazývá realtime predictions.
Po kliknutí se zobrazí velmi jednoduché rozhraní, kam se vloží údaje podobně, jako ty, co jsme generovali do CSV a on nám ukáže náhled na predikci, kterou pro dané vstupní hodnoty má.
Zde je vidět, že se jedná o SPAM s pravděpodobností 0.826366662979126, protože náš práh je 0.82, tak je to e-mail označen korektně za SPAM.
Takto jednoduše jsem si ověřil, že to může fungovat. WOW! Pár hodin, bez programátora. Něco, co by před pár lety stálo stovky tisíc Kč s nejistým výsledkem.
Dalším krokem bylo nahodit to do testování v rámci SupportBoxu. Amazon má připraveny skvělé knihovny, takže se jen vytvořil bod připojení pro daný ML a v kódu se přidalo pár řádků. ML vrací strukturu podobnou, jako je v obrázku výše, kde stačí pouze vzít predikci z predictedLabel a je hotovo.
Asi týden jsme to takto nechali jet čistě na mé schránky a vše jsme logovali. Výsledky vypadaly luxusně, odchytili jsme odhadem asi 3x více spamů, než předtím. A za celou dobu jsem našel jen jeden e-mail, který spamem neměl být (ale i na první pohled jsem to nepoznal, byla to nějaká podivně stylovaná nabídka).
Následně jsme to nasadili pro všechny zákazníky a ti si to mohou sami zapnout.
Poté, co si tento spamfiltr začali zákazníci aktivovat, a má jej aktivní pouze hrstka lidí, týdně zachytíme cca 2.5x více spamu, než předtím, který nedorazí k našim zákazníkům. Takže ušetříme našim zákazníkům v součtu desítky hodin (možná i stovky) denně, při třídění pošty. Tento čas mohou věnovat užitečnějším činnostem. A to se počítá.
Celkem nám to vymyslet, otestovat, nasadit zabralo <10h. Cena je také směšná. Za 12 dní v červenci nás to stálo $1.3. Takže cca $0.10 za den.
Zajímavé je srovnání, když se ML trénuje na vzorku 1.000 vstupních hodnot a 6.000 hodnot. Rozdíl v kvalitě predikcí 6x většího vzorku dat je <15 %. Což je super zjištění, protože dokážeme natrénovat odděleně ML pro různé jazyky už z malého vzorku dat. Stejně tak dokážeme dělat individuální spamfiltry pro specifické zákazníky, kterým nechodí tolik zpráv.
Díky tomuto experimentu jsem se ponořil do ML a co vše lze díky této technologii docílit. Nápadů máme už teď několik. Postupně je budeme přidávat a dělat tak SupportBox chytřejší. Ale vše má svůj čas. Během prázdnin dokončíme moduly pro live chat a telefony a staneme se tak full-stack řešením zákaznické péče.
Pokud tě článek zaujal, dej mi vědět do komentáře. Případně, pokud máš dotazy k některé části, rád je rozepíšu podrobněji, či doplním.