Categories
Offsites

torch 0.2.0 – Initial JIT support and many bug fixes

We are happy to announce that the version 0.2.0 of torch just
landed on CRAN.

This release includes many bug fixes and some nice new features
that we will present in this blog post. You can see the full
changelog in the NEWS.md
file.

The features that we will discuss in detail are:

  • Initial support for JIT tracing
  • Multi-worker dataloaders
  • Print methods for nn_modules

Multi-worker dataloaders

dataloaders now respond to the num_workers argument and will run
the pre-processing in parallel workers.

For example, say we have the following dummy dataset that does a
long computation:

library(torch) dat <- dataset( "mydataset", initialize = function(time, len = 10) { self$time <- time self$len <- len }, .getitem = function(i) { Sys.sleep(self$time) torch_randn(1) }, .length = function() { self$len } ) ds <- dat(1) system.time(ds[1])
 user system elapsed 0.029 0.005 1.027 

We will now create two dataloaders, one that executes
sequentially and another executing in parallel.

seq_dl <- dataloader(ds, batch_size = 5) par_dl <- dataloader(ds, batch_size = 5, num_workers = 2)

We can now compare the time it takes to process two batches
sequentially to the time it takes in parallel:

seq_it <- dataloader_make_iter(seq_dl) par_it <- dataloader_make_iter(par_dl) two_batches <- function(it) { dataloader_next(it) dataloader_next(it) "ok" } system.time(two_batches(seq_it)) system.time(two_batches(par_it))
 user system elapsed 0.098 0.032 10.086 user system elapsed 0.065 0.008 5.134 

Note that it is batches that are obtained in parallel, not
individual observations. Like that, we will be able to support
datasets with variable batch sizes in the future.

Using multiple workers is not necessarily
faster than serial execution because there’s a considerable
overhead when passing tensors from a worker to the main session as
well as when initializing the workers.

This feature is enabled by the powerful callr package and works in all
operating systems supported by torch. callr let’s us create
persistent R sessions, and thus, we only pay once the overhead of
transferring potentially large dataset objects to workers.

In the process of implementing this feature we have made
dataloaders behave like coro iterators. This means that
you can now use coro’s syntax for looping
through the dataloaders:

coro::loop(for(batch in par_dl) { print(batch$shape) })
[1] 5 1 [1] 5 1

This is the first torch release including the multi-worker
dataloaders feature, and you might run into edge cases when using
it. Do let us know if you find any problems.

Initial JIT support

Programs that make use of the torch package are inevitably R
programs and thus, they always need an R installation in order to
execute.

As of version 0.2.0, torch allows users to JIT trace torch R
functions into TorchScript. JIT (Just in time) tracing will invoke
an R function with example inputs, record all operations that
occured when the function was run and return a script_function
object containing the TorchScript representation.

The nice thing about this is that TorchScript programs are
easily serializable, optimizable, and they can be loaded by another
program written in PyTorch or LibTorch without requiring any R
dependency.

Suppose you have the following R function that takes a tensor,
and does a matrix multiplication with a fixed weight matrix and
then adds a bias term:

w <- torch_randn(10, 1) b <- torch_randn(1) fn <- function(x) { a <- torch_mm(x, w) a + b }

This function can be JIT-traced into TorchScript with jit_trace
by passing the function and example inputs:

x <- torch_ones(2, 10) tr_fn <- jit_trace(fn, x) tr_fn(x)
torch_tensor -0.6880 -0.6880 [ CPUFloatType{2,1} ]

Now all torch operations that happened when computing the result
of this function were traced and transformed into a graph:

tr_fn$graph
graph(%0 : Float(2:10, 10:1, requires_grad=0, device=cpu)): %1 : Float(10:1, 1:1, requires_grad=0, device=cpu) = prim::Constant[value=-0.3532 0.6490 -0.9255 0.9452 -1.2844 0.3011 0.4590 -0.2026 -1.2983 1.5800 [ CPUFloatType{10,1} ]]() %2 : Float(2:1, 1:1, requires_grad=0, device=cpu) = aten::mm(%0, %1) %3 : Float(1:1, requires_grad=0, device=cpu) = prim::Constant[value={-0.558343}]() %4 : int = prim::Constant[value=1]() %5 : Float(2:1, 1:1, requires_grad=0, device=cpu) = aten::add(%2, %3, %4) return (%5)

The traced function can be serialized with jit_save:

jit_save(tr_fn, "linear.pt")

It can be reloaded in R with jit_load, but it can also be
reloaded in Python with torch.jit.load:

import torch fn = torch.jit.load("linear.pt") fn(torch.ones(2, 10))
tensor([[-0.6880], [-0.6880]])

How cool is that?!

This is just the initial support for JIT in R. We will continue
developing this. Specifically, in the next version of torch we plan
to support tracing nn_modules directly. Currently, you need to
detach all parameters before tracing them; see an example
here
. This will allow you also to take benefit of TorchScript
to make your models run faster!

Also note that tracing has some limitations, especially when
your code has loops or control flow statements that depend on
tensor data. See ?jit_trace to learn more.

New print method for nn_modules

In this release we have also improved the nn_module printing
methods in order to make it easier to understand what’s
inside.

For example, if you create an instance of an nn_linear module
you will see:

nn_linear(10, 1)
An `nn_module` containing 11 parameters. ── Parameters ────────────────────────────────────────────────────────────────── ● weight: Float [1:1, 1:10] ● bias: Float [1:1]

You immediately see the total number of parameters in the module
as well as their names and shapes.

This also works for custom modules (possibly including
sub-modules). For example:

my_module <- nn_module( initialize = function() { self$linear <- nn_linear(10, 1) self$param <- nn_parameter(torch_randn(5,1)) self$buff <- nn_buffer(torch_randn(5)) } ) my_module()
An `nn_module` containing 16 parameters. ── Modules ───────────────────────────────────────────────────────────────────── ● linear: <nn_linear> #11 parameters ── Parameters ────────────────────────────────────────────────────────────────── ● param: Float [1:5, 1:1] ── Buffers ───────────────────────────────────────────────────────────────────── ● buff: Float [1:5]

We hope this makes it easier to understand nn_module objects. We
have also improved autocomplete support for nn_modules and we will
now show all sub-modules, parameters and buffers while you
type.

torchaudio

torchaudio
is an extension for torch developed by Athos Damiani (@athospd), providing audio
loading, transformations, common architectures for signal
processing, pre-trained weights and access to commonly used
datasets. An almost literal translation from PyTorch’s Torchaudio
library to R.

torchaudio is not yet on CRAN, but you can already try the
development version available here.

You can also visit the pkgdown website for examples
and reference documentation.

Other features and bug fixes

Thanks to community contributions we have found and fixed many
bugs in torch. We have also added new features including:

You can see the full list of changes in the NEWS.md
file.

Thanks very much for reading this blog post, and feel free to
reach out on GitHub for help or discussions!

The photo used in this post preview is by
Oleg Illarionov
on
Unsplash

Categories
Misc

Scotland’s Rural College Makes Moo-ves Against Bovine Tuberculosis with AI

Each morning millions of bleary-eyed people pour milk into their bowls of cereal or cups of coffee without a second thought as to where that beverage came from. Few will consider the processes in place to maintain the health of the animals involved in milk production and to ensure that the final product is fit Read article >

The post Scotland’s Rural College Makes Moo-ves Against Bovine Tuberculosis with AI appeared first on The Official NVIDIA Blog.

Categories
Misc

Ubuntu install help

Hi there! I am brand new to unbuntu and I have just build a
computer running it. I am currently trying to download TensorFlow
for my computer and I am trying to run the comamnd:

$. ./venv/bin/activate.fish # fish

and it’s returning this:

bash: ./venv/bin/activate.fish: line 4: syntax error near
unexpected token `-d’

bash: ./venv/bin/activate.fish: line 4: `function deactivate -d
“Exit virtualenv and return to normal shell environment”‘

Any thoughts?

submitted by /u/Elrekl

[visit reddit]

[comments]

Categories
Misc

layers with zero parameters have no weights?

When we print model.summary(), it shows the number of parameters
associated with each layer. When the number is zero, it means there
are no weights associated with this layer. Is that correct?

A very basic question but I just want to confirm. Having issues
with loading pretrained weights ‘by_name’, hence trying to
debug.

submitted by /u/juggy94

[visit reddit]

[comments]

Categories
Offsites

Privacy Considerations in Large Language Models

Machine learning-based language models trained to predict the next word in a sentence have become increasingly capable, common, and useful, leading to groundbreaking improvements in applications like question-answering, translation, and more. But as language models continue to advance, new and unexpected risks can be exposed, requiring the research community to proactively work to develop new ways to mitigate potential problems.

One such risk is the potential for models to leak details from the data on which they’re trained. While this may be a concern for all large language models, additional issues may arise if a model trained on private data were to be made publicly available. Because these datasets can be large (hundreds of gigabytes) and pull from a range of sources, they can sometimes contain sensitive data, including personally identifiable information (PII) — names, phone numbers, addresses, etc., even if trained on public data. This raises the possibility that a model trained using such data could reflect some of these private details in its output. It is therefore important to identify and minimize the risks of such leaks, and to develop strategies to address the issue for future models.

If one prompts the GPT-2 language model with the prefix “East Stroudsburg Stroudsburg…”, it will autocomplete a long block of text that contains the full name, phone number, email address, and physical address of a particular person whose information was included in GPT-2’s training data.

In “Extracting Training Data from Large Language Models”, a collaboration with OpenAI, Apple, Stanford, Berkeley, and Northeastern University, we demonstrate that, given only the ability to query a pre-trained language model, it is possible to extract specific pieces of training data that the model has memorized. As such, training data extraction attacks are realistic threats on state-of-the-art large language models. This research represents an early, critical step intended to inform researchers about this class of vulnerabilities, so that they may take steps to mitigate these weaknesses.

Ethics of Language Model Attacks
A training data extraction attack has the greatest potential for harm when applied to a model that is available to the public, but for which the dataset used in training is not. However, since conducting this research on such a dataset could have harmful consequences, we instead mount a proof of concept training data extraction attack on GPT-2, a large, publicly available language model developed by OpenAI, that was trained using only public data. While this work focuses on GPT-2 specifically, the results apply to understanding what privacy threats are possible on large language models generally.

As with other privacy- and security-related research, it is important to consider the ethics of such attacks before actually performing them. To minimize the potential risk of this work, the training data extraction attack in this work was developed using publicly available data. Furthermore, the GPT-2 model itself was made public by OpenAI in 2019, and the training data used to train GPT-2 was collected from the public internet, and is available for download by anyone who follows the data collection process documented in the GPT-2 paper.

Additionally, in accordance with responsible computer security disclosure norms, we followed up with individuals whose PII was extracted, and secured their permission before including references to this data in publication. Further, in all publications of this work, we have redacted any personally identifying information that may identify individuals. We have also worked closely with OpenAI in the analysis of GPT-2.

The Training Data Extraction Attack
By design, language models make it very easy to generate a large amount of output data. By seeding the model with random short phrases, the model can generate millions of continuations, i.e., probable phrases that complete the sentence. Most of the time, these continuations will be benign strings of sensible text. For example, when asked to predict the continuation of the string “Mary had a little…”, a language model will have high confidence that the next token is the word “lamb”. However, if one particular training document happened to repeat the string “Mary had a little wombat” many times, the model might predict that phrase instead.

The goal of a training data extraction attack is then to sift through the millions of output sequences from the language model and predict which text is memorized. To accomplish this, our approach leverages the fact that models tend to be more confident on results captured directly from their training data. These membership inference attacks enable us to predict if a result was used in the training data by checking the confidence of the model on a particular sequence.

The main technical contribution of this work is the development of a method for inferring membership with high accuracy along with techniques for sampling from models in a way that encourages the output of memorized content. We tested a number of different sampling strategies, the most successful of which generates text conditioned on a wide variety of input phrases. We then compare the output of two different language models. When one model has high confidence in a sequence, but the other (equally accurate) model has low confidence in a sequence, it’s likely that the first model has memorized the data.

Results
Out of 1800 candidate sequences from the GPT-2 language model, we extracted over 600 that were memorized from the public training data, with the total number limited by the need for manual verification. The memorized examples cover a wide range of content, including news headlines, log messages, JavaScript code, PII, and more. Many of these examples are memorized even though they appear infrequently in the training dataset. For example, for many samples of PII we extract are found in only a single document in the dataset. However, in most of these cases, the originating document contains multiple instances of the PII, and as a result, the model still learns it as high likelihood text.

Finally, we also find that the larger the language model, the more easily it memorizes training data. For example, in one experiment we find that the 1.5 billion parameter GPT-2 XL model memorizes 10 times more information than the 124 million parameter GPT-2 Small model. Given that the research community has already trained models 10 to 100 times larger, this means that as time goes by, more work will be required to monitor and mitigate this problem in increasingly large language models.

Lessons
While we demonstrate these attacks on GPT-2 specifically, they show potential flaws in all large generative language models. The fact that these attacks are possible has important consequences for the future of machine learning research using these types of models.

Fortunately, there are several ways to mitigate this issue. The most straightforward solution is to ensure that models do not train on any potentially problematic data. But this can be difficult to do in practice.

The use of differential privacy, which allows training on a dataset without revealing any details of individual training examples, is one of the most principled techniques to train machine learning models with privacy. In TensorFlow, this can be achieved with the use of the tensorflow/privacy module (or similar for PyTorch or JAX) that is a drop-in replacement for existing optimizers. Even this can have limitations and won’t prevent memorization of content that is repeated often enough. If this is not possible, we recommend at least measuring how much memorization occurs so appropriate action can be taken.

Language models continue to demonstrate great utility and flexibility—yet, like all innovations, they can also pose risks. Developing them responsibly means proactively identifying those risks and developing ways to mitigate them. We hope that this effort to highlight current weaknesses in large language modeling will raise awareness of this challenge in the broader machine learning community and motivate researchers to continue to develop effective techniques to train models with reduced memorization.

Acknowledgements
This work was performed jointly with Florian Tramer, Eric Wallace, Matthew Jagielski, Ariel Herbert-Voss, Katherine Lee, Adam Roberts, Tom Brown, Dawn Song, Ulfar Erlingsson, Alina Oprea, and Colin Raffel.

Categories
Misc

Meet the Researcher, Rommie Amaro, Simulating the SARS-CoV-2 virus with AI and HPC

This month we spotlight Rommie Amaro, professor and endowed chair in the Department of Chemistry and Biochemistry at the University of California, San Diego.

‘Meet the Researcher’ is a new series in which we spotlight different researchers in academia who are using GPUs to accelerate their work. This month we spotlight Rommie Amaro, professor and endowed chair in the Department of Chemistry and Biochemistry at the University of California, San Diego.

Amaro is also the principal investigator of the Amaro Lab, which is broadly concerned with the development and application of state-of-the-art computational and theoretical techniques to investigate the structure, function, and dynamics of complex biological systems for applications to drug discovery.

This year, she led a team of 28 researchers at a number of different institutions, combining high performance computing (HPC) and AI to provide the clearest view to date of the coronavirus, winning a special Gordon Bell Prize in November 2020.

What are your research areas of focus?

I like to call myself a computational biophysical chemist. In general, we use computational models to explore biological and chemical systems. The idea of being able to use mathematics and computing to understand how biological systems work is just fascinating to me. Over the years, we’ve applied this to areas such as cancer and DNA editing.

What motivated you to pursue your recent research area of focus in supercomputing and the fight against COVID?

We had been working for a number of years on influenza virus, and so after 7-8 years of work on that, we published a paper in February on simulating the influenza virus envelope. That project was really a labor of love. It presented, for the first time, molecular simulations of a lipid enveloped virus in atomic detail. The size was 160 million atoms, very large, and to get to that point we had to overcome multiple technical challenges to simulating viruses in such detail.

When SARS-CoV-2 hit, it was an immediate and natural pivot to focus on COVID. As soon as the McLellan group deposited the spike structure in the bioRxiv, we scooped up the data and started working with it, aiming to simulate the complete spike structure in all its atomic detail.

Simulation of SARS-CoV-2

What problems does your research address?

There’s this aspect of the virus that’s very intriguing. Viruses in general have evolved something called a glycan shield, which is basically a sugary coating that the virus uses to mask itself from the human immune system.

All of the cells in our body are coated with different types of sugar molecules, called glycans. The viruses have evolved this way of looking just like other human cells by covering themselves in the same soft of sugary coating. That way, when viruses get into our bodies, our immune system doesn’t see spike protein, it sees this sugary coating. Since it looks like any other cell, the human body doesn’t recognize it as a threat and therefore doesn’t activate the immune system response.

Experimentally, we know these glycans are there but can’t take pictures of them because the sugars move around quite a bit, one can’t get a crisp image of what they actually look like. This is where computing has a lot to give because we can basically create an atomic level structure of what those sugar molecules look like and then that gives us the picture of the sugar structures and what they’re doing. That’s what our research addresses.

Our simulations gave people the first views of what the glycan shield looks like on the viral spike protein. For researchers, it’s not only knowing where that shield is, but it’s even more critical knowing where the shield is not because there are holes in the shield, vulnerabilities of the virus. We can use that information to understand where and how antibodies bind and how to use this information in the design of novel therapeutics.

Simulation of SARS-CoV-2 spike protein 

What is the (expected) impact of your work on the field/community/world?

The reason that we care about simulating the virus in all its atomic detail is that it helps us understand how the virus works, the mechanisms of viral infection, as well as to understand and design new therapeutics. For example, drug molecules that target different virus protein molecules or different parts of the virus. It also helps us understand how antibodies work, their design with vaccines. Having information about where all the atoms are and what they’re doing is really critical.

How have you used NVIDIA technology in your current research?

The main tool my team is using is molecular dynamics simulations. We like to think of this tool as a computational microscope. We take data from different sources, bring these data streams together to create these highly detailed, accurate models of the virus.

The simulations run on chips like NVIDIA GPU systems, and use supercomputing sites that use NVIDIA GPUs. The kind of math these simulations require ports super well to GPUs. That’s where NVIDIA technology has been transformative: it’s allowed us to speed up our calculations tremendously. It’s basically making our microscope really powerful–getting better, more accurate views of the virus much faster. The sooner we have that information, the sooner we can develop drugs and therapeutics to fight the virus.

What were some of the challenges you faced while pursuing your research?

This whole year has been extraordinary. It’s a really crazy time to be a scientist, in the sense of being on the front lines trying to understand the mysteries of COVID-19. There’s so much data coming in from all over the world. We’ve had so many sleepless nights since February/March, working around the clock.

At the same time, there’s been so many amazing collaborations. So many people around the world focused on one single problem. This doesn’t happen, typically we’re each working on different things.

What’s next for your research?

We’re just at the beginning, there’s so much we want to do. Now that we’ve got the virus built and simulated, and that was honestly an incredible feat in terms of how fast we were able to do it, the next is to build and simulate the host cell, the human cell. We want to understand how the virus latches on because it’s a pretty complex process.

Another aspect I’m really excited to study—there are a lot of questions about how and why the virus is airborne transmissible. One of the things we’re planning to do next is to build aerosol particles that have the virus inside of them. These systems will have about one billion atoms. This will help us understand what’s happening to the virus in the air and how long it lives and how it can infect people under a range of conditions, such as relative humidity.

There’s just so much to do.

Any advice for new researchers, or early career professionals, especially to those who are inspired and motivated by your work?

Find your passion. It won’t necessarily be science for everybody. We need so many kinds of people to make the world go round.

Find that thing that lights you up, that you just want to keep coming back to. When I was at university and Saturday came around, everyone would go tailgating. I looked forward to going into the lab. When you really find your passion, your work doesn’t feel like your job. And when your passion unites with the ability to serve others or a greater good, it’s so incredibly rewarding.

Also, education is super important–stay at it, stay it in, to get a better life. 

Categories
Offsites

Personal Assistant Kino Part 1 – Overview

Kino 프로젝트는 QS를 통해서 자신에 대해서 알고, 불필요한 일들을 자동화시키고 삶의 질을 증진시키기 위한 프로젝트 입니다.

images

출처 : http://quantifiedself.com/

지금까지의 시리즈

Github: https://github.com/DongjunLee/quantified-self

Introduction

최근에 Bot에 대한 글도 많이 읽고.. 조그만 미니 프로젝트로 Bot도 개발해보면서, 그 동안 마음 속에 계속해서 자리잡고 있던! 제가 가장 만들어보고 싶던 개인 프로젝트를 진행할 때가 되었구나 생각이 되었습니다.

그 프로젝트는 바로.. 개인용 비서 Bot을 만드는 프로젝트입니다. 다른 누구도 아닌 오직 나 자신만을 위한 개인 비서를 만들어보자라는 생각은 예전부터 했었고, 그것에 대비하여 Toggl 을 통해서 내가 보내는 시간을 기록하고, RescueTime 을 통해서는 어떤 프로그램을 사용하고, 생산성은 어떠한지 기록하고 있었습니다. 그 외에는 Pebble Time을 통해서 걸음걸이와 수면시간 또한 Tracking이 되고 있었습니다. 그리고 Todoist 를 통해서는 일정관리를 하고 있었습니다. 이렇듯 저에 대한 정보들은 수치화된 데이터가 되어 여기저기 쌓이고 있던 것이죠.

그래서 이렇게 쌓은 나에 대한 Data를 바탕으로.. 나를 아는 Bot을 만들고 싶다는 생각을 해왔습니다. 물론 위의 서비스들은 대부분 API를 제공하고 있는 상황입니다.

images

Data 수집 정리

  1. Toggl: 시간을 트래킹하기 편한 앱. 일을 시작하기전에 타이머를 누르고, 일이 끝나면 타이머를 종료해서 내가한 작업들을 기록하는데 많이 사용한다.
  2. RescueTime: 생산성을 관리해주는 툴로서, PC에서 사용한 앱들의 시간을 기록해서 보여줍니다.
  3. Pebble: 걸음걸이와 수면시간을 Tracking. Data는 스마트워치 안에 기록되는 시스템으로 보이나.. 간편하게 사용하기에는 어려워 보이네요.
  4. Todoist: 온라인 작업 관리 및 할일 목록 관리 앱 입니다. 스마트폰, PC, 웹 등.. 다양한 플랫폼을 제공하고 있어서 편하게 사용하고 있습니다.
  5. 그 외 수면 시간, 행복도, 집중도, 생산성 데이터를 수집하는 App (없을 경우 Bot에 붙여서 만들기)

Bot Platform

Bot을 개발하기 이전에 Data 수집에 대한 셋팅은 위와 같이 맞춰놓고, 다음으로 무엇으로 Bot 만들 것인가.. 고민을 해보았습니다. 최근에 Telegram, Facebook Messenger, Line 등.. 많은 Messaing App 기업들이 Bot API를 공개하고 있지만, 개인용으로 사용하기에는 조금 부적합한 면들이 있었습니다.

그렇게 알아보던 중, 제가 사용하고 있는 개인용 Slack이 눈에 들어왔습니다. IFTTT를 연동하여 여러 서비스들에 대한 정보를 Slack에 기록하고 있었고, 개인적인 메모를 하거나 정보를 볼 때 사용하고 있었습니다. 또한 Slack은 굉장히 간단하게 BOT_TOKEN 만 있어도 통신을 주고 받을 수 있고, Slack으로 Salady Bot을 만들면서 이미 개발경험을 가지고 있기에 더욱 적합하다고 생각을 했습니다.

images

출처 : Slack

Slack의 선정이유

  1. 개인용으로 만들어서 운영하는 Slack이 있다. (개인용으로 사용가능)
  2. 다른 App들은 Server로 구성하고, Webhook 설정들의 작업들이 필요하지만, Slack은 Token만 있으면 통신이 가능.
  3. 이미 Slack Bot을 개발해본 경험이 있다.
  4. Team용으로 이미 친숙하게 사용하고 있었다.
  5. 외부 서비스들을 Integration 해서 사용하기 쉽다.

Chat Bot

최근에 Chat Bot이 큰 화두가 되면서, 여러가지 bot에 대한 글을 많이 접하기도 하고 api.ai, wit.ai, 최근 한국에서는 AMICA.ai, fluenty.ai 등의 프레임워크들도 나오면서 쉽게 Chat Bot을 만들 수 있게 되었고.. 조금 더 대중적이게 되었습니다.

이러한 Bot 프레임워크를 사용하다보면 Bot의 Flow도 대략적으로 감이 오고, 어떤 방식으로 이루어져있는지 알 수가 있습니다. 대부분의 프레임워크에서는 NLP 엔진을 이용해서 intent, named entity, sentiment, domain 등을 추출하고, 그에 대한 답을 사용자가 입력하여 연결하는 방식으로 진행이 됩니다. 아직은 Short-term 즉, 조금 전에 대화했던 것들을 기억해서 처리하는 것은 잘 해내지만, Long-term 조금 더 오래된 대화의 경우, 그 대화를 기억하고 말을 이어가는 것은 훨씬 어렵습니다. 그래서 위의 bot 프레임워크들도 long-term까지 지원하는 것을 목표로 개발하고 있습니다.

그래서 제가 생각하기에 봇은 크게 3가지 종류의 봇으로 구분이 된다고 생각을 합니다.

  1. Basic Chatbot: Bot이 그저 하나의 UX인 경우입니다. 정해진 입력에 따라서 정해진 응답을 하는 경우입니다. 보통 정규화 표현식으로 입력을 처리하게 되고, 여기서는 NLP가 들어가지 않습니다.
  2. Smart Chatbot: 이 단계부터는 NLP가 적용된 단계입니다. 각종 Bot framework에서 제공하는 기능처럼, intent, named entity, sentiment, domain 등을 추출하여 그에 따른 응답을 처리합니다. 여기서는 Dialog manager가 대화를 파악하고 관리하며, 자연스러운 응답을 생성하는 NLG까지 포함됩니다.
  3. A.I Chatbot: 이 단계의 Bot은 강 인공지능을 의미합니다. 아직은 어떤 모습으로 나타날지 상상할 수 없는 모습이기도 합니다. Deep Learning + Reinforce Learning 가 합쳐지면서 조금씩 조금씩 이 단계를 향해 나아가고 있다고 생각합니다.

여기서 제가 만들고자 하는 Bot의 목표는 우선.. Smart Chabot 입니다. 하지만 문제는 Data가 어느정도 필요하다는 문제가 있습니다.

그래서 보통 Basic Chatbot부터 시작을 하여 Data를 모으는 것이 일반적 입니다. 그리고 일정량의 Data가 모인 다음에 기존의 로직을 바탕으로 학습을 하는 Imitation Learning을 통해 자동화를 시킬 수 있습니다. 그 후로 더 데이터를 모으고, 기준이 생긴다면 그 것에 맞춰서 조금 더 똑똑하게 행동하도록 만들 수 있을 것 입니다.

저는 이와 같은 장기프로젝트에 대한 계획을 세우면서, 이 과정에서 필요한 기능들이 무엇인지 떠올랐습니다.
우선, 개인용 봇으로 사용하는데, 괜히 어렵게 말을 알아들을 필요가 없다는 것 입니다. 최소한의 자연어 처리를 하고 간단한 키워드 매칭을 통해서 의도를 파악하는 것.
다음으로 새로운 기능들을 다 만들 필요없이 기존의 서비스들을 사용해서 기능들을 만들 것.
마지막으로 나에게 필요한 기능을 내가 지정한 시간에 실행할 수 있는 것.

그렇게 여러가지 서비스들을 Kino의 Skill 들로 등록해서 사용하고, 간단한 자연어 처리로 간단하게 Job을 등록해서 내가 원하는 시간에 그 일을 하도록 만들었습니다 (예, 2시간 마다 날씨 알려줘, 오전 8시에 하루 브리핑 등…) 아래는 지금까지 Kino의 중간 결과물 입니다.

다음에는 Skill과 Scheduling 에 대해서 조금 더 세부적인 내용들을 다뤄보겠습니다.

Kino

그렇게 만들기 시작한 저만의 개인 비서 Kino. 아래는 중간 결과물을 입니다.

skill_example1

Weather Skill

skill_example2

Kino는 아침에 스케쥴을 알려줍니다

guide

인트로 & 가이드

functions

사용할 수 있는 Skill들
Categories
Offsites

Personal Assistant Kino Part 2 – Chatbot의 기본구조 Skill & Scheduler

Kino 프로젝트는 QS를 통해서 자신에 대해서 알고, 불필요한 일들을 자동화시키고 삶의 질을 증진시키기 위한 프로젝트 입니다.
이번 편에서는 가장 기본이 되는 Skill (기능) 등록과 스케쥴링 관리에 대해서 다룹니다.

images

출처 : http://quantifiedself.com/

지금까지의 시리즈

Github: https://github.com/DongjunLee/quantified-self

Skill & Scheduler

Kino에 대해서 간단히 소개를 했던 1편에 이어서, 내부의 핵심이 되는 Skill과 Scheduler 기능에 대해서 이야기하고자 합니다. 이 두가지 기능은 다음과 같은 생각들을 하다가 나오게 되었습니다.

어떻게 하면 나에게 맞는 똑똑한 개인용 봇을 만들 수 있을까?

  1. IFTTT 같은 서비스 처럼 내가 사용하는 서비스들을 자유롭게 Customizing 해서 사용한다면 좋겠다.
  2. 그렇다면 이렇게 만든 함수들을 Skill로 명명하고 관리해야겠다.
  3. 마지막으로 내가 원하는 시간에 이 Skill이 돌아가도록 할 수 있다면?

이 Skill과 Scheduler 를 조금 더 세부적으로 보면 이렇습니다.
외부 서비스의 API를 wrapping해서 custom한 function을 만든다. 그리고 crontab 기능을 이용해서 정해진 시간에 그 기능이 돌아가도록 한다.

이렇게 2가지 기능에 대한 세부적인 내용들이 나오고, 어떻게 구현하는 것이 좋을지 간단한 설계 후 작업을 진행하였습니다. 저는 이 kino 프로젝트를 진행하면서 한가지 중요하게 생각했던 부분이 있습니다. ‘Python 3.6을 이용해서 새롭게 나온 Feature들을 최대한 활용하자.’ 그래서 구현에 대한 설명에도 새로운 Feature들이 포함되어 있습니다. 이 글을 읽으시는 독자 분들이 Python 3.6의 매력을 느낀다면 좋겠습니다.

Skill

Skill은 계속해서 추가될 수 있기 때문에, 프로젝트 구조에서부터 나누는 것이 필요했습니다.

- functions.py : skills에 있는 함수들을 등록하는 파일
- skills : Skill들을 모아놓는 디렉토리
	- weather.py : 날씨 skill
	- todoist.py : Todoist skill
	- ....

다음으로는 ‘어떻게 Skill을 사용할 것 인가’ 입니다.
저는 처음에 간단한 Keyword 매칭 만으로 Skill 을 사용할 생각이였으나.. 모든 Keyword 들을 다 입력해 놓는 것은 좋은 방법이 아니였습니다. Keyword 들을 입력하는 것도 큰 수고가 필요하기 때문에, 조금 더 간결하게 사용할 수 있는 방법을 생각해보았습니다. 그래서 추가된 것이 disintegrator 입니다.

여기서 간단한 NLP 를 사용합니다. 한글의 경우 konlpy가 형태소 분석이나 품사태깅의 기능을 지원합니다. konlpy를 이용해서 하려는 작업은 간단합니다. 문장을 그대로 받아서 Simple하게 만드는 것.

class KorDisintegrator:

    def __init__(self):
        self.ko_twitter = Twitter()

    def convert2simple(self, sentence="", norm=True, stem=True):
        disintegrated_sentence = self.ko_twitter.pos(
            sentence, norm=norm, stem=stem)
        convert_sentence = []

        for w, t in disintegrated_sentence:
            if t not in ['Eomi', 'Josa', 'KoreanParticle', 'Punctuation']:
                convert_sentence.append(w)
        return " ".join(convert_sentence)

위 코드는 신정규님께서 Python 2016에서 발표하신 프로그램 참고하였습니다.
이 KorDisintegrator 를 실제 문장이 통과하면 어떻게 되는지 보시죠!

>>> disintegrator.convert2simple(sentence="키노야 날씨 어때?")
'키노 날씨 어떻다'
>>> disintegrator.convert2simple(sentence="키노야 날씨 알려줘!")
'키노 날씨 알다'

이렇게 간단한 문장으로 변하게 되고, 이제 키워드를 쓸때 고려하면 되는 문장은 원형을 사용하면 되는 것이죠.

이제 문제는 Keyword를 어디에 저장할까? 그리고 skill에 필요한 param은 어떻게 관리할까? 였습니다.
처음에는 ‘외부에 새로 파일을 하나 만들어 skill에 대한 정보를 가지고 있도록 할까?’ 였습니다. 음.. 그렇다면 Bot을 시작할 때, Skill들에 대한 정보를 읽어서 skills.json이라는 파일을 만들면 어떨까? 저는 이 방법이 괜찮다고 생각이 들었고, 여기서 python의 __doc__, __annotations__을 이용하게 됩니다.

아래는 실제 Skill로 사용하고 있는 Code입니다.

def forecast(self, timely: str="current"):
    """
    keyword: ["날씨", "예보", "weather", "forecast"]
    description: "Weather forecast"
    icon: ":sun_with_face: "
    """

    ...
    weather.forecast(timely=timely)

여기서 timely: str 은 Python 3.6에서 새로 추가된 type annotation 기능입니다.
여기서 timely의 타입을 입력해놓으면..

>>> forecast.__annotations__
{"timely": str}

__annotations__를 통해서 필요한 param 정보를 얻어올 수 있습니다. 마찬가지로 __doc__을 이용하면 아래 적혀있는 keyword, description, icon에 대해서 얻어올 수 있습니다. 그래서 이 정보들을 모아서 skills.json 파일을 만들면 Skill 등록은 끝이나게 됩니다.

다음으로는 Python에서 제공하는 any(), all()을 사용해서 키워드 매칭 코드를 작성하고,
Regex(정규식)을 통해서 Skill의 Param을 전달하는 코드를 작성하면!
아래와 같이 날씨 스킬을 손쉽게 사용할 수 있습니다. 참 쉽죠?

images

Scheduler

Skill을 이제 추가하고 사용할 수 있는 구조를 정립했으니, scheduler를 만드려고 합니다.
Python에는 schedule 이라는 스케쥴링을 손쉽게 사용할 수 있도록 도와주는 Package가 있습니다.

아래는 schedule Github페이지에 나와있는 간단한 예제코드입니다. 다른 설명이 필요없이 아주 직관적으로 구성되어있습니다.

schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)

schedule Package를 이용하면 제가 작업하면 되는 부분은

  1. 백그라운드에서 스케쥴링을 돌린다.
    • Threading 을 사용.
  2. 동적으로 스케쥴링을 돌리도록 하는 것.
    • Python에서 제공하는 built-in funciton인 getattr을 사용

이 부분에 대한 자세한 코드를 알고 싶으시다면, Github 저장소를 참고해주세요! 다음으로 이 함수대로만 사용하는 것은 조금 제한적인 부분들이 있어서 아래와 같은 조건을 추가하게 됩니다.

Between : 시간대를 나타냄. schedule에서는 10분 마다, 1시간 마다 이렇게도 조작할 수 있기 때문에 특정 시간대에 10분 마다, 1시간 마다를 가능하게 하도록 하기 위하여 추가하였습니다.

images

이제 제가 원하는 대로 Scheduling을 사용할 수 있는 준비가 되었습니다!
다음으로는 간단하게 자연어로 Scheduling을 등록하고 작업을 진행시킬 수 있으면 되겠네요.

여기서도 간단한 Keyword 매칭을 사용합니다.

images

이렇게 Scheduling 기능까지 추가를 완료하였습니다!

Example

이제 이 기능들이 실제로 어떻게 쓰이는지 같이 보시죠!

images

images

이렇게 일을 시작하면, 등록된 Scheduling Job 들에 따라서 진행이 됩니다.

images

  • 10시 ~ 22시까지 2시간마다 날씨
  • 오전 8시 하루 프리핑
  • 오후 10시 남은 작업 알려주기 등..

위의 예시들은 실제로 제가 사용하고 있는 Scheduling Job 들 입니다.

이 정도면 제법 개인 비서처럼 행동할 수 있을 것 같지 않나요? 😀
이렇게 Kino 는 똑똑해지고 저를 위한 비서가 되고 있습니다!

다음에는 손쉽게 Todoist에 있는 작업들을, Trello에 카드를 통해 관리하며.. 자동으로 Toggl에 시간 기록까지 되고, 마지막에는 작업 리포트도 받을 수 있는 T3 기능에 대해서 다루도록 하겠습니다.

모든 코드는 여기서 확인하실 수 있습니다.
Kino를 더욱 똑똑하게 만들도록 도와주시는 분들은 언제든 환영입니다^^

Categories
Offsites

Personal Assistant Kino Part 3 – 작업을 최대한 간편하게 관리하고, 데이터를 기록하자

Kino 프로젝트는 QS를 통해서 자신에 대해서 알고, 불필요한 일들을 자동화시키고 삶의 질을 증진시키기 위한 프로젝트 입니다. 이번 편에는 사용하고 있는 다양한 앱들을 연결하여 사용하는 작업 간편 관리 기능에 대해서 이야기 합니다.

images

출처 : http://quantifiedself.com/

지금까지의 시리즈

Github: https://github.com/DongjunLee/quantified-self

저번 편인 Part 2 - Skill & Scheduler 은 Kino가 내가 원하는 대로 돌아가도록 준비하는 과정이였습니다. 이제 이 프로젝트의 목표인 Quantified Self를 다루려고 합니다. 나 자신에 대한 데이터를 손쉽게 모으고, 차트를 보며 피드백을 나 자신에게 주고, 이를 통해 삶의 질을 증진시키는 과정을 말이지요.

T3 (Todoist + Toggl + Trello)

오늘 다루려는 이야기는 Task에 관한 이야기입니다. 저는 Todoist를 굉장히 애용하고 있습니다. Premium 기능으로 업그레이드해서 사용할 정도로 말이죠. 모바일, 데스크탑 전부 사용할 수 있는 app이 있어서 언제 어디서든 간편하게 To do list를 관리할 수 있었습니다.

여기서 더 나아가 나는 작업들을 진행할 때, 시간이 얼마나 걸리는지.. 그리고 이 작업에 대해서는 얼마나 집중을 했는지, 하루의 시간을 어떻게 보냈는지 알고 싶었습니다.

제가 원하는 것들을 충족하기 위해서는 Todoist를 사용하는 것만으로는 부족했습니다. 그래서 필요한 서비스들을 찾아보게 되었습니다. 시간 측정에는 Toggl이 가장 잘 만들어진 서비스였고, 작업을 시작하고 (Doing), 끝내는 것(Done)을 가장 쉽게 다룰 수 있는 것은 Trello칸반 보드를 통해서 Task, Doing, Done 의 리스트로 관리 하는 것이라는 결론을 낼 수 있었습니다.

그렇게해서 만들어진 것이 T3

즉, T3 = Todoist + Toggl + Trello 를 통한 Task 간편 관리 기능입니다.
아래는 T3에 사용되는 Skill들 입니다.

Todoist

  • 🌆 today_briefing : Todoist에 등록된 Task들을 브리핑합니다.
  • 📃 todoist_remain : 남은 작업들에 대해서 안내합니다.

Toggl

  • ⌚️ toggl_timer : Toggl Timer 시작 혹은 정지.
  • 🔔 toggl_checker : 30분 마다 시간 체크. (150분 이상 작업 시, 휴식 추천)
  • 📊 toggl_report : Toggl task 리포트.

Trello

  • 📋 kanban_init : Trello 보드를 초기화 합니다.
  • 📋 kanban_sync : Todoist의 Task들과 Trello 보드의 싱크를 맞춥니다.

Question

  • ✍️ attention_question : 작업 후, 집중도 물어보기 (100점 만점)

  • ✍️ attention_report : 집중도 리포트

작업 관리 시나리오

이렇게 Kino Slack Bot에 연결된 스킬들을 통해서 유기적으로 작업들이 돌아가게 됩니다. 이 프로젝트에서 가장 초점을 맞추고 있는 것 중에 하나가 직접 데이터를 기록하기 위한 노력을 최대한 줄이는 것이기 때문이죠.

위의 스킬을 기준으로 조금 더 자세히 설명드리면 다음과 같습니다.
아침이 되면, Todoist 에 등록된 일감들이 Trello 보드에 자동으로 추가가 됩니다. (kanban_init)

images

여기에서 Tasks 에 있는 작업을 Doing 으로 옮기게 되면, 그때 Toggl의 시간 기록이 동작하게 됩니다.

images.png

단순하게 해당 작업을 끝낸 후에는 Done으로 옮기면 Toggl 시간 기록 역시 정지가 되고, 집중도를 물어보게 되어있습니다.

images.png

그리고 이렇게 카드를 옮겨주면서 작업을 진행해주면, 밤에 이런 리포트를 생성해주도록 되어 있습니다.

images

toggl_report Skill

이상이 제가 하루의 Task를 관리하는 시나리오입니다.
제가 하는 것이란 Trello의 카드를 옮기는 것 뿐이에요. 참 간단하죠?

Quantified Self에서 가장 중요한 것은 데이터를 손쉽게 모을 수 있어야하고, 한눈에 볼 수 있는 차트를 제공함으로서 간편하게 자기자신에게 피드백을 줄 수 있어야 한다는 것 입니다. 그런 의미로 T3는 굉장히 간편하고 유용한 기능입니다. 그리고 Task 관련 데이터들을 Toggl에 쌓여있으므로, 언제든 데이터를 받을 수 있고 더 복잡한 분석 또한 할 수 있을 것 입니다.

Trello Webhook

Skill들을 Python으로 wrapping 되어있는 package 들을 사용하면 간편하게 내가 원하는 커스텀 스킬들을 만들 수 있습니다. 각각 서비스에 필요한 TOKEN, ACCESS_KEY 등을 준비하고 연결하면 손쉽게 끝낼 수 있습니다.

그 외에 작업이 필요한 부분은 Webhook입니다. IFTTT에서도 Trello를 연결해서 사용할 수 있지만, 기본적으로 IFTTT는 실시간이 아닙니다. 하지만 Trello로 Task들을 관리하려면 실시간으로 반응을 해야합니다. 작업을 시작한다고 Doing에 올린지 10분이나 지나서 Toggl Timer가 작동하는 것은 너무나도 불편하니까요.

Trello에서는 Webhook를 추가할 수 있도록 지원하고 있습니다. 이 Webhook을 처리하려면 callback을 처리하는 간단한 서버가 있어야 합니다. 이 callback을 처리하기 위해서 Server를 빌리는 것은 너무 아깝습니다. 이럴때는 Serverless Framework를 사용해서 간단하게 처리할 수 있습니다. AWS에 대한 간략한 설정을 마치고, callback에 대한 함수를 정의한다음 배포를 하면 AWS API Gateway + Lambda가 자동설정 되는 것을 보실 수 있습니다.

def kanban_webhook(event, context):
    input_body = json.loads(event['body'])
    print(event['body'])

    action = input_body["action"]
    action_type = action["type"]

    if action_type == "createCard":
        list_name, card_name = get_create_card(action["data"])
    elif action_type == "updateCard":
        list_name, card_name = get_update_card(action["data"])

    kanban_list = ["DOING", "BREAK", "DONE"]
    if list_name in kanban_list:
        payload = make_payload(action=list_name, msg=card_name)
        r = send_to_kino({"text": payload})
    ...

kino-webhook 여기에서 kanban_webhook이 구현되어 있습니다.

이제 Webhook을 다 정의했으니, 이 Webhook을 Kino가 처리하면 모든 문제는 끝이 납니다! 아래는 카드 이동에 따라서 Skill들의 연결을 정리해놓은 것입니다.

   def KANBAN_handle(self, event):
        toggl_manager = TogglManager()

        action = event['action']
        description = event['msg']
        if action.endswith("DOING"):
            toggl_manager.timer(
                description=description,
                doing=True,
                done=False)
        elif action.endswith("BREAK"):
            toggl_manager.timer(doing=False, done=False)
        elif action.endswith("DONE"):
            toggl_manager.timer(doing=False, done=True) ## Todoist 연결되어 있음
  • Doing : Toggl Timer 시작

  • Done : Toggl Timer 정지 & Todoist 작업 완료

  • Break : Toggl Timer 정지

Monotasking, 한 번에 한가지 일에만 집중을

T3 라는 이름의 작업 관리기능을 만들게 된 것에 대해서는 데이터 수집 이외에도 이유가 하나 더 있습니다.
이렇게 칸반으로 작업을 관리하게 되면, 자연스럽게 강제되는 것이 있습니다. 바로 멀티테스킹을 하지 않도록 되는 것이죠.
멀티태스킹은 여러가지 작업을 동시에 하면서 더 빠르게 작업들을 할 수 있다고 생각을 하게 되지만, 실상은 그렇지 않다고 합니다.

≪정리하는 뇌≫ 의 저자 대니얼 J. 래비틴에 말에 따르면 이렇습니다

우리는 자기가 멀티태스킹을 하고 있다고 생각하지만, 이것은 강력하고도 사악한 착각이다. MIT의 신경과학자이자 분할 주의(divided attention)의 세계적 권위자인 얼 밀러는 우리 뇌가 멀티태스킹에는 별로 적합하지 않게 만들어져 있다고 말했다. 사람들은 자기가 멀티태스킹을 하고 있다고 생각하지만, 실제로는 한 과제에서 다른 과제로 아주 신속하게 전환하고 있을 뿐이라는 것이다.
(중략 …)
멀티태스킹은 투쟁-도피 호르몬인 아드레날린은 물론 스트레스 호르몬인 코르티솔의 생산도 증가시킨다. 또한 뇌를 과도하게 자극해 생각을 뒤죽박죽으로 만든다. 멀티태스킹은 도파인 중독 피드백 고리를 만들어내고, 보상작용을 통해 뇌가 초점을 잃고 끊임없이 외부자극을 찾아 나서게 만든다. 설상가상으로 전전두엽피질은 새로움 편향이 있다. 무언가 새로운 것이 등장하면 쉽게 주의를 뺏긴다는 의미다. – 154 페이지 중에서

물론, 멀티태스킹이 실제로 가능한 사람들도 있다고 합니다. 굉장히 소수의 사람들이라고 하고 대부분의 사람들에게는 한 번에 하나의 일에 집중하는 것이 더 효율적이라고 합니다. 저 역시 한번에 여러가지를 잘 하지는 못하는 사람이기에 이렇게 한번에 한가지 일에 집중하는 시스템을 통해서 강제해보려고 합니다. Doing 에 개발 작업을 옮겼다면, 딱 그 작업만 할 수 있게 말이죠.

끝으로

이번 T3에서는 여러가지 서비스들과 Kino를 전부 연결해서 작업을 간편하게 관리하고, 차트를 제공하는 T3 기능에 대해서 살펴보았습니다. 이렇게 하루하루 Task에 대한 데이터들을 모아서 내가 어떤 작업에 잘 집중하는지, 어느 시간대에 집중을 잘 하는지.. 이런 여러가지 분석을 할 수 있을 것 입니다. 저도 데이터를 모으는 중이라, 나중에 꼭 분석하려고 합니다. 😀

모든 코드는 여기서 확인하실 수 있습니다.

다음에는 최신 Feed를 바로바로 알려주고, 자동으로 모은 데이터를 통해서 분류까지 알아서 하는 Smart Feed 기능에 대해서 알아보겠습니다.

Categories
Offsites

Personal Assistant Kino Part 4 – 자주 읽은 글들은 자동으로 저장하는 Smart Feed

Kino 프로젝트는 QS를 통해서 자신에 대해서 알고, 불필요한 일들을 자동화시키고 삶의 질을 증진시키기 위한 프로젝트 입니다. 이번 편에서는 자동으로 자주 읽는 글들을 저장해주는 Smart Feed 에 대해서 다뤄보고자 합니다.

images

출처 : http://quantifiedself.com/

지금까지의 시리즈

Github: https://github.com/DongjunLee/quantified-self

저번 편에서 Kino의 T3, Task들에 대해서 자동으로 기록하고, 리포팅도 해주는 Task Master 로서의 기능을 살펴보았습니다. 이번 편에는 제가 애용하고 있는 또 하나의 기능. Feed & Pocket 에 대해서 다뤄보고자 합니다.

RSS Feed

RSS Feed는 많은 웹사이트에서 제공하는 RSS를 사용해서 새로운 Article이 등록 되었을 때, 알림을 받을 수 있는 기능을 말합니다. 여기서 잠시 RSS에 대해서 알고 넘어가겠습니다.

RSS(Rich Site Summary)는 뉴스나 블로그 사이트에서 주로 사용하는 콘텐츠 표현 방식이다. 웹 사이트 관리자는 RSS 형식으로 웹 사이트 내용을 보여 준다. 이 정보를 받는 사람은 다른 형식으로 이용할 수 있다.RSS 리더에는 웹기반형과 설치형이 있다. 웹기반형 리더는 간단한 계정등록으로 어디에서든 이용할 수 있다는 장점을 가지고 있다. – 위키백과 RSS

기본적으로 많은 웹사이트들이 RSS를 제공하고 있습니다. 그리고 이것을 이용하는 서비스들도 많이 있지요. 그 중 하나가 Feedly 라는 서비스 입니다. 자주 들어가서 보는 사이트들을 등록해두면, 편하게 새로운 글들을 볼 수 있습니다. 저는 이 서비스를 잘 사용하고 있었지만, 제가 원하는 기능들을 전부 지원하고 있지는 않았습니다.

Pocket

그리고 제가 애용하는 또 하나의 서비스는 Pocket 입니다. 이 서비스가 하는 일은 아주 간단합니다.

When you find something you want to view later, put it in Pocket.

무언가 나중에 읽고 싶은 Article이 생기면, Pocket 에 넣고 아무때나 편하게 보면 되는 것이죠. 저는 유심히 읽고 싶은 Article에 대해서는 Pocket에 저장을 하곤 합니다. 그리고 읽다가 정말 좋은 글이면 Favorite로 옮겨놓곤 하죠.

Smart Feed

저는 이렇게 새로운 글들을 훑어보고, 관심있는 글들을 Pocket에 저장하고, 읽다가 좋다고 느껴지는 글을 Favorite로 옮기는 저의 패턴을 자동화하고 싶었습니다. 그래서 생각하고 만들게 된 기능이 Smart Feed 입니다.

먼저 이 기능에 필요한 것은 RSS 주소들 입니다. 그래야 여기서 RSS를 읽고 새로운 글이 나오면 저장을 하던 알림을 주던 할 수 있겠죠. 그래서 만들게 된 awesome-feeds Repository 입니다. 자주 보는 웹사이트들의 RSS를 Git으로 관리를 하면 편할 것 같기도 하고, 여러 좋은 RSS 주소를 가지고 있는 awesome 시리즈로 만들고 싶었습니다.

이제 RSS가 준비 되었으니, 최신 글이 등록되면 알림을 주면 됩니다!
여기에서는 feedparser를 사용했습니다.

f = feedparser.parse(feed_url)

f.entries = sorted(
    f.entries, key=lambda x: x.get("updated_parsed", 0), reverse=True
)

# get Latest Feed
noti_list = []
if feed_url in cache_data:
    previous_update_date = arrow.get(cache_data[feed_url])
    for e in f.entries:
        e_updated_date = arrow.get(e.updated_parsed)
        if e_updated_date > previous_update_date:
            noti_list.append(self.__make_entry_tuple(category, e, feed_name))

스케쥴 기능은 2편 Skill & Scheduller 에서 다룬 것처럼 지정할 수 있습니다. 매분마다 Feed를 새로 확인하는 것은 과부하가 크기 때문에, 제가 테스트를 해봤을 때는 20분 정도의 interval이면 충분하다고 느껴졌습니다.

def __excute_feed_schedule(self, interval):
    schedule.every(interval).minutes.do(
        self.__run_threaded,
        self.function_runner,
        {
            "repeat": True,
            "func_name": "feed_notify",
            "params": {},
            "day_of_week": [0],
            "not_holiday": False,
        },
    )

이제 Kino가 최신 RSS Feed 들을 바로바로 알려주고 있습니다. 지금도 유용하기는 하지만, 여기서 더 나아가 만들고 싶은 기능이 있었습니다. 제가 무조건 Pocket에 저장을 하는 이미 신뢰받고 있는 웹사이트들은 바로 자동으로 저장을 하는 것!

이것 역시 Pocket 을 연동하고, 간단한 Classification 알고리즘이면 똑똑하게 만들 수 있습니다. 기계학습에서 가장 중요한 것은 Data 입니다. 이런 데이터는 Log들을 이용하면 간단히 만들 수 있습니다. 먼저 Feed 기능에서 알림을 주는 모든 글을 전체 data로 볼 수 있습니다. 이 중에서 Pocket에 저장되는 글만 label 값을 1로 주면, 자연스럽게 전체 데이터들이 관심있는 글 / 관심 없는 글로 나뉘게 됩니다. 여기에 웹사이트의 이름까지 정보로 준다면, 간단한 Decision Tree를 만들 수 있습니다.

images

출처: 위키백과

예를 들어, Google AI Blog 웹사이트에서 새로운 글이 등록 되었을 때, 제가 그 동안 여기서 봤던 글이 총 5개이고, 그 중 4개를 Pocket에 저장했다면, 새로운 글도 관심을 가질만한 글이라고 보는 것이죠.

Decision Tree는 scikit-learn 을 이용하면 아주 간단하게 사용할 수 있습니다.

class FeedClassifier:
    def __init__(self):
        train_X = FeedData().train_X
        train_y = FeedData().train_y
        
        model = tree.DecisionTreeClassifier()
        model.fit(train_X, train_y)  # Training
        self.clf = model

    def predict(self, link, category):
        result = self.clf.predict(category_id)[0]
        if result == FeedDataLoader.TRUE_LABEL:
            ...
        else:
            ...

Online Learning

다음으로 중요한 것은, online learning 입니다. 제가 Pocket에 넣는 Feed들은 그때그때 달라지게 됩니다. 그에 맞춰서 모델 또한 이러한 변화를 감지하고 최신의 정보를 가지고 판단을 해야합니다. 이때 사용되는 방법이 online learning 입니다.

지속적으로 새로운 데이터를 모형에 적용해 모형이 항상 최신의 상태로 유지되기 하는 방식

키노의 Smart Feed는 이 방식을 통해서, 더 똑똑해지고 있습니다. online learning은 하나의 싸이클을 만들어주는 것으로 가능해집니다.

images

  1. Logging: 알람을 받고 있는 Feed의 모든 정보들, 그 중에서 Pocket에 저장한 Feed들 정보
  2. Data Processing: Log를 파싱하여 카테고리, 제목, 날짜, 링크 등의 정보로 가공하고, 라벨 또한 추가해줍니다. (0: Pocket에 추가하지 않음 / 1: Pocket에 추가)
  3. Model: 준비된 데이터를 모델에 Fit 시킵니다. (Training)
  4. Predict: 훈련된 모델을 기반으로 새로운 Feed를 보고 Pocket에 저장할지 말지 판단합니다. 그리고 이때 모델이 잘못 내린 판단에 대해서 Feedback을 제공하여 올바른 라벨이 저장되도록 합니다.

여기서 실시간으로 학습하는 것이 부담이 된다면, 하루에 한번 새로 학습시키는 것도 방법이 될 수 있을 것 입니다.

Conclusion

이번에는 아주 간단한 기능이지만, 정말 유용한 Smart Feed 기능을 살펴보았습니다. 현재는 단순하게 Count를 기반으로 하고 있기 때문에 좀 더 정교한 예측을 하지는 못 합니다. 추후에 Text Classification 문제로서 제목이나 소개글을 통해서 제가 관심을 가질만 한 글인지 예측하도록 만들 생각입니다. 또한 Text Summarization 문제로 다가선다면, 바쁜 저를 위해서 요점만 쏙쏙 정리해줄 수도 있을 것 입니다. 이렇게 Smart Feed 기능의 발전가능성은 열려있다고 생각이 듭니다. 데이터를 많이 모아서, 얼른 Deep Learning 모델로 교체를 해야겠네요!

모든 코드는 여기서 확인하실 수 있습니다.