Como crio um serviço de recomendação da comunidade VKontakte

O verão estava terminando, agosto estava especialmente frio. Minha 11ª série começou e percebi que agora é a última chance (spoiler: não) de melhorar de alguma forma minha competência profissional. Durante vários anos, tenho trabalhado diligentemente em vários projetos de TI, alguns sozinhos, outros na equipe. Mas agora todos os filhos da namorada de minha mãeestão fazendo algo bonito. Talvez inútil, mas bonito na aparência. Alguém faz uma simulação pegajosa de partículas na forma de gifs, alguém mergulha no aprendizado de máquina e faz todo tipo de transferência de estilos. E o que eu sou pior? Eu também quero!

Um exemplo de simulação também está em cat.


Exemplo de simulação de partículas de um amigo meu

Foi com esse pensamento que meu estudo sobre o tópico de aprendizado de máquina começou. E em termos de treinamento para mim, não havia nada de novo, como em qualquer outro campo da TI, a prática é necessária aqui. Mas e se eu não estiver interessado em nenhum analisador de tonalidade? Devemos inventar algo próprio.

Mais uma vez folheando o feed de notícias do VKontakte, percebi que as comunidades dessa rede social são um verdadeiro tesouro para a ciência de dados. Se você processar textos, memes na forma de figuras ou músicas de coleções, poderá obter uma enorme quantidade de informações relevantes sobre as pessoas modernas: gêneros de música popular, vocabulário ou a hora do dia da atividade da maioria das pessoas. Este é um campo para muitas descobertas.

Mas quanto essas estatísticas serão necessárias para as pessoas comuns? Como se eu sentisse falta da minha música ou não consiga acessar a seção "Popular"? Portanto, você precisa pensar em algo prático, algo que possa atrair pelo menos uma porcentagem significativa de usuários.

Vale a pena notar que, alguns meses antes, li um artigo interessante sobre como criar meu mecanismo de pesquisa em casa , o que realmente me impressionou. Como o autor, senti um grande desejo por grandes projetos que processam um grande número de milhares de gigabytes de informações dia e noite.



E agora, voltamos a agosto, que ficou um pouco mais quente do que no começo do artigo. Quando percebi que agora tenho uma enorme fonte de informação, percebi que estava na hora. Chegou a hora de nosso próprio sistema monstruoso. Mas a questão principal permaneceu alguns dias depois - o que devo fazer com tudo isso? O que oferecer ao usuário? Não vou atormentar o leitor, apenas direi que, como alguns de meus amigos, é muito difícil para mim procurar novos grupos do VKontakte que eu possa gostar. Agora, todo primeiro público tem um nome - um conjunto aleatório de palavras. Os administradores tentam torná-lo o mais absurdo, provavelmente este é algum tipo de corrida, compreensível apenas para eles.

E então eu decidi escrever um serviço que ajudará o usuário na escolha das comunidades, recomendar o que você pode se inscrever. Então, minha ideia surgiu.

A introdução foi longa, não por acaso, era para transmitir minhas emoções e mostrar que a idéia não apareceu do nada. Na verdade, como quaisquer outras idéias sobre Habré.

Meu serviço ainda está em operação, já dura mais de quatro meses (se você contar desde o momento do primeiro experimento bem-sucedido). Mas eu já tenho uma experiência que quero compartilhar com você. Agora, haverá uma descrição curta e concisa do projeto. A seguir, descreverei alguns pontos-chave. E se o artigo atrair especialmente os habrayuzers, sua continuação será publicada, que conterá informações e códigos mais puramente técnicos.

Tudo consiste em três partes:

  • bot de pesquisa (se você pode chamar assim)
  • mecanismo de processamento de dados
  • site para usuários (com um painel de controle e monitoramento para administradores)

A funcionalidade do bot inclui a pesquisa de novos grupos e o texto "strip" e outras informações no banco de dados. O mecanismo está envolvido no processamento posterior desses dados, sobre os quais irei escrever abaixo. E o site simplesmente permite que os usuários usem tudo isso.

Pesquisar bot


Nada de novo aqui. Eu apenas pego o perfil de uma pessoa no VK e recebo uma lista de grupos e amigos dele. Tudo isso acontece com a API VK. E se esse IPA conseguir obter uma lista de grupos do usuário e de seus amigos, ele não conseguirá obter o conteúdo dos grupos ... Eu apenas encontro uma restrição e é isso. Então me lembrei de que, há algum tempo, a VKontakte estava promovendo seu sistema legal apenas para essas coisas. E o nome desse sistema é API de streaming.
API de streaming - uma ferramenta para obter uma seleção aleatória de registros da VK. Na página de descrição, está escrito que você pode obter apenas 1% de todas as informações. Para obter até cem, você precisa escrever para o Suporte e explicar suas intenções para eles.
Parece que tudo é maravilhoso. Mas não. Eu, como provavelmente muitos, perdi a palavra mais importante na descrição acima. E esta é a preposição "antes". Ninguém vai fornecer todos os 100% dos dados. Esta é apenas uma barra superior bonita e é isso. De fato, ficamos assim:


O Hope Agent # 365 não vai me odiar todos os 365 dias do ano para esta captura de tela

Ou seja, só posso receber 30 mil eventos por dia. E esse número inclui comentários e apenas republicações. Também é necessário indicar algumas palavras-chave, somente mensagens com elas aparecerão. Algumas das postagens restantes simplesmente não me interessam, pois estão na parede dos usuários. Permanece um pouco. Para referência, na minha implementação atual, posso receber até 8,5 milhões de registros em alguns dias de tempo de atividade incompleto (no total - cerca de 10 horas, mas não houve medições precisas).

Aqui eu tenho que dizer sobre uma regra que identifiquei de todo esse experimento. Nunca julgue um grupo por um post. Especialmente se você é uma inteligência artificial suscetível a esse ruído. Portanto, você precisa de pelo menos algumas postagens para criar uma descrição objetiva do público. Agora, vamos estimar que alguns grupos com conteúdo realmente de alta qualidade o liberam a cada poucas semanas. E mesmo assim, posso ignorá-lo devido à imperfeita API de streaming. E se eu conseguir, por quanto tempo devo coletar o conteúdo pouco a pouco?

Decidi isso por muito tempo e segui o outro caminho. Como não consigo obter uma resposta clara do VKontakte no formato JSON, analisarei os muros das comunidades. Sim, a tarefa é um pouco complicada e sua solução fica mais lenta, mas não tenho alternativa. Foi assim que comecei a escrever o primeiro bloco do meu sistema. A propósito, escrevi em Java usando o Jsoup, uma biblioteca que torna muito conveniente extrair conteúdo de texto HTML. Não esqueci de processar a data de publicação da última postagem, não preciso de comunidades mortas, simplesmente não as indexo. As postagens marcadas com anúncios também são descartadas. Nem todos os administradores fazem essas anotações, mas esse problema não é tão simples de resolver, não pude criar um filtro adequado para publicidade e, por isso, por enquanto, recuso essa filtragem.

Engine


Esta é provavelmente a parte mais interessante do projeto, mas não descreverei tudo em detalhes nesta publicação. Se alguém estiver interessado nos detalhes, peça-me todas as formas possíveis.

A maneira mais simples de apresentar texto em um formato compreensível para uma rede neural é o saco de palavras.



Processo de vetorização e mais sobre o BOW
Eu preparo um dicionário de todas as palavras comuns com antecedência (sem esquecer de excluir as mais comuns, como "a", "o que", "quais" e outras; elas não distinguem seu texto do plano de fundo de outras), cada palavra tem seu próprio número. Então, quando preciso processar o texto com uma rede neural, obtenho o número de cada palavra do dicionário (se houver) e recebo um vetor (também conhecido como array na programação). Esse é um conjunto ordenado de números, no qual existe uma unidade no lugar de cada número de palavra do texto (veja a figura acima). Acontece que um tipo de dados é bastante compreensível para a rede. O comprimento de cada vetor é 30.000, sobre tantas palavras adequadas que coletei nos primeiros estágios do desenvolvimento.

Também é importante não esquecer que, por exemplo, as palavras "habr" e "(c) habr" são quase as mesmas para compreensão. Mas para o algoritmo descrito acima, essas são palavras completamente diferentes. Para corrigir isso, eu uso o analisador morfológico JMorphy2 . Essa é a porta do PyMorphy2 original para Java. Ele pode fazer muitas coisas legais, por exemplo, alterar a forma de uma palavra (caso, sexo, número, etc.). Eu preciso dele para obter a forma inicial da palavra. Como você sabe, as formas iniciais de palavras "idênticas" são as mesmas. E isso resolve o problema acima.

 6929  21903  25126  11441  7374  1925  1626  23128  6241  25584 

Um exemplo de uma lista de palavras em um dicionário e seus números (separados por um espaço)

A lista acima mostra que a palavra "dragão" não se transformou em "dragão". Isso está um pouco errado, mas mesmo esse pré-processamento de texto é suficiente. Em geral, esta biblioteca possui muitos erros, mas a maioria deles não afeta a operação do sistema.

O serviço é destinado a um público de língua russa. E, por simplicidade, apenas o russo está sendo processado. Todos os caracteres (letras entre eles) de outros alfabetos são jogados fora, como sinais de pontuação, números, emojis ... Mais uma vez, simplificação. Além disso, não esqueça de filtrar palavras de idiomas que usam parcialmente o alfabeto russo, mas adicione suas próprias letras (ucraniano, por exemplo).

Mas continuarei a partir do momento em que qualquer postagem do VKontakte já se transformou em um vetor (eu chamo de vetorização). Aqui o seguinte link está conectado: uma rede neural. Decidi usá-lo porque era interessante para mim e consegui encontrar uma arquitetura adequada para minha tarefa. O primeiro artigo da série "Auto Encoders in Keras" me ajudou com isso. E sim, decidi usar o codificador automático mais comum, pois é benéfico em termos de velocidade e treinamento. Mas vamos falar sobre tudo em ordem.

Como em todos os outros auto-codificadores, você precisa criar duas redes neurais (codificador e decodificador) e combiná-las em uma. Fiz o seguinte:

 from keras.layers import Input, Dense, Flatten, Reshape from keras.models import Model #    encoding_dim = 64 #  inp = Input(shape=(30000, )) # 30000 -  #     encoded = Dense(encoding_dim, activation='linear')(inp) #  #     input_encoded = Input(shape=(encoding_dim,)) decoded = Dense(30000, activation='sigmoid')(input_encoded) #          encoder = Model(inp, encoded, name="encoder") decoder = Model(input_encoded, decoded, name="decoder") autoencoder = Model(inp, decoder(encoder(inp)), name="autoencoder") 

Mas por que precisamos de duas redes? Enfim, o autor, você não descreveu por que isso é tudo !

Calma, agora tudo será. Para treinar, por exemplo, apenas um codificador é impossível - simplesmente não ficará claro o quão correta a previsão que ele fez. E para isso, treinamos a segunda rede, que decodificará imediatamente a saída da primeira (decodificador). Os mesmos dados de entrada e saída também são usados. Muitas redes (denominadas autoencoder) aprendem a obter o mesmo com os dados de entrada. Mas todos os dados passam por um "gargalo" estreito na forma de 64 neurônios. Isso descarta as informações mais desnecessárias. Assim, as redes neurais aprendem a transmitir informações importantes sobre o texto com a máxima qualidade e eliminam todo o ruído. Depois, retiro o decodificador e pronto. Você pode obter um resultado melhor, mas precisa aumentar a dimensão da camada de saída do codificador / decodificador de entrada. Então será necessário armazenar mais valores no banco de dados, ele pesará mais + todas as operações em vetores longos serão mais longas (mais sobre isso mais tarde). Ou você pode adicionar camadas / neurônios, mas o treinamento e a vetorização serão mais longos.

O próprio codificador permite "compactar a dimensão do vetor". Lembra daquele vetor de zeros e uns? Portanto, o codificador permite alterar seu tamanho de 30 K para 64 sem muita perda de informações importantes. Após esta etapa, você normalmente pode comparar os dois vetores para determinar sua similaridade ...

Mas analisamos o trabalho do serviço por recomendação das comunidades VK, e não registros individuais. Isso significa que precisamos, de alguma forma, obter o vetor de todo o público. Isso é feito com muita facilidade, matemática no nível da quinta série. Este é um método um pouco grosseiro, mas funciona. Eu apenas pego e adiciono todos os vetores de registro de uma comunidade (por exemplo, pegue três vetores pequenos {1, 2, 3}, {2, 3, 4}, {0, 4, 2}, obtemos o vetor {3, 9, 9 }). E divido cada elemento pelo número de vetores (obtemos o vetor {1, 3, 3}). É tudo, combinamos todos os registros do grupo em um. No futuro, você precisará criar algo mais complicado, para poder emitir ruídos na forma de postagens com publicidade, por exemplo. Mas agora isso é suficiente.

Nos voltamos para a parte matemática em si, mas como todo mundo tem medo, por algum motivo, eu assino o máximo possível. Vamos começar com vetores no sentido matemático. Vetor é um segmento direcionado. É uma coisa que tem as coordenadas do começo (é mais conveniente levá-las com zeros) e as coordenadas do final. É o último que é gravado entre chaves. Por exemplo, as coordenadas do final do vetor {1, 0, 1} youtube são um ponto com coordenadas (1, 0, 1). Mas vamos considerar dois vetores bidimensionais,  veca{5, 2} e  vecb{5, 0}. Vamos construí-los em um sistema de coordenadas:



Deixe o vetor  vecaarosa  vecbaamarelo. Então, pelo fato matemático da nona classe, o cosseno do ângulo entre eles é igual à razão entre seu produto escalar e o produto de seus módulos.

Produto Escalar <  veca,  vecb> igual à soma dos produtos dos elementos correspondentes, temos < veca, vecb>=55+20=25.

O módulo vetorial é encontrado pela seguinte fórmula:

| veca|= sqrtax2+ay2


Onde axe ayeste é o primeiro e o segundo valor do vetor a, respectivamente. Então:
|a|= sqrt52+22= sqrt29
|b|= sqrt52+02=5

Combinando tudo de acordo com a fórmula, obtemos:
cos( veca, vecb)= frac25 sqrt295 aproximadamente0,93
A correção dos cálculos pode ser verificada através das funções trigonométricas do triângulo retângulo formado. No projeto, todos os cálculos são realizados de acordo com essas fórmulas, mas apenas as coordenadas do final do vetor não são duas, mas sessenta e quatro.

O que essas informações fornecem? Como se viu, quanto maior o valor do cosseno (quanto menor o ângulo), mais semelhantes os textos que correspondem aos vetores. Assim, a tarefa de encontrar o grupo mais semelhante ao grupo A se resume a encontrar o cosseno do ângulo entre o vetor desse grupo e todos os outros. Então o mecanismo sai de todos os grupos para os quais o valor do cosseno, juntamente com A, será maior que, digamos, 0,99. Nesta fase, você pode simplesmente exibir o resultado, como eu tinha antes. Mas esse processo já é muito longo em 100 mil comunidades, e o que acontecerá, por exemplo, na 1M?

Para resolver esse problema, eu uso o gráfico. Todos os grupos são representados como seus vértices e dois pontos são conectados se o cosseno do ângulo entre os vetores correspondentes a eles for maior que 0,99. Mas se você não entender a estrutura com o nome do gráfico, poderá imaginar que eu pré-calculo os pares de comunidades mais semelhantes no banco de dados e os salvo. E não esqueço de atualizar o gráfico à medida que novos grupos são adicionados ao banco de dados. Sim, é muito tempo, mas ainda mais fácil para o usuário do que era antes.

Site


Não vou pintar tudo no site, pois essa é a parte mais fácil e chata. Eu nunca escrevi sites do zero, sempre usei vários mecanismos prontos. Mas neste projeto, percebi que seria mais fácil fazer uma samopis. Portanto, o mecanismo do site é escrito em Python 3 usando o Flask. E o mecanismo de modelo Ninja2 é usado, o que torna mais conveniente substituir valores dinâmicos no código HTML (e js) estático. Não esqueci a autorização pelo VKontakte, pois essa é a opção mais ideal. O designer, assim como o designer de layout, é péssimo da minha parte, se alguém quiser participar do projeto - seja bem-vindo.


A primeira linha de resultados do site

Os problemas


Eu encontrei algumas situações desagradáveis ​​que resolvi com sucesso. O problema com a API VK foi escrito acima e sua solução foi especialmente desagradável para o serviço, pois a velocidade caiu muito. Se antes eu recebi centenas de postagens em uma solicitação, agora preciso fazer alguns downloads de código HTML grande, analisá-lo e somente depois desse processo. Agora, há um problema com a restrição de conseguir usuários, amigos e grupos, mas esse limite não interfere realmente nesse estágio. Então você tem que resolvê-lo da mesma maneira que o primeiro.

O texto na Internet moderna está se tornando menos significativo a cada dia. Por muitos anos, o VKontakte tem muitos grupos com vídeos, fotos e música. E para obter boas recomendações, você precisa processá-las.



Mas isso não é texto, e é necessário um poder de computação realmente sério. Por exemplo, esta é uma placa de vídeo de ponta, mas agora não tenho uma e não quero usar um servidor para tudo isso (é muito cedo). Mas, em geral, eu já tenho as melhores práticas para arquitetura de rede neural para esta tarefa. Vou usar algum neurônio para classificar as imagens, "cortando" a parte superior, responsável pela classificação dos objetos. Tudo o que resta será o que mapeará os sinais da imagem. Posso apertar este cartão com outro codificador e isso é tudo, todas as operações subseqüentes são semelhantes às de "texto".

Resta outra pergunta não resolvida sobre quantas solicitações ao site do VKontakte posso fazer por unidade de tempo. Ou em um dia. Agora não encontrei essa restrição, mas isso pode acontecer no momento mais inoportuno.

Planos futuros


Preciso urgentemente de um belo painel de controle e estatísticas. Ele já está em seu estado inicial, mas precisa ser finalizado. A partir disso, eu quero controlar o início / parada dos microsserviços (ou seja, o mecanismo consiste deles), o tamanho das filas, a velocidade de processamento e tudo mais. Bem, estatísticas, quem não gostaria de ver seus números? Obviamente, preciso otimizar tudo e torná-lo adequado para os usuários; em particular, preciso refazer a parte externa do site, pois ele não atende aos meus padrões de conveniência.

Conclusão


Consegui embarcar no caminho de criar um serviço com uma estrutura interessante (pelo menos para mim) que vou usar em um dos concursos que me permitirão ingressar na melhor universidade russa (não vou dizer que tipo de primeira não clássica é). Acho que, se você ainda trabalha, pode extrair algo mais interessante, por exemplo, um analisador da qualidade das publicações, fazer um serviço de análise para a administração da comunidade ou algo mais.

Me deparei com muitas coisas do texto acima pela primeira vez. Isso significa que eu poderia fazer algo errado. Se meus leitores souberem o que pode ser melhorado / corrigido, onde posso ter outros problemas e assim por diante - escreva sobre isso no comentário. E peço que você faça críticas sobre a própria qualidade do artigo, para que eu possa melhorá-lo da próxima vez. Obrigada

Source: https://habr.com/ru/post/pt436636/


All Articles