DeepMorphy é um analisador morfológico baseado em rede neural para o idioma russo.
DeepMorphy é um analisador morfológico para o idioma russo. Disponível como biblioteca .Net Standard 2.0. Pode:
A terminologia em DeepMorphy é parcialmente emprestada do analisador morfológico pymorphy2.
Grammeme (grammeme inglês) - o significado de uma das categorias gramaticais de uma palavra (por exemplo, pretérito, singular, masculino).
Uma categoria gramatical é um conjunto de gramas mutuamente exclusivos que caracterizam alguma característica comum (por exemplo, gênero, tempo verbal, caso, etc.). Uma lista de todas as categorias e gramáticas suportadas no DeepMorphy está aqui.
Tag (tag inglesa) - conjunto de gramas que caracterizam uma determinada palavra (por exemplo, uma tag para a palavra ouriço - substantivo, singular, caso nominativo, masculino).
Lema (lema inglês) é a forma normal de uma palavra.
Lematização (eng. lematização) - trazendo uma palavra à sua forma normal.
Um lexema é um conjunto de todas as formas de uma palavra.
O elemento central do DeepMorphy é a rede neural. Para a maioria das palavras, a análise morfológica e a lematização são realizadas pela rede. Alguns tipos de palavras são processados por pré-processadores.
Existem 3 pré-processadores:
A rede foi construída e treinada no framework tensorflow. O dicionário Opencorpora serve como conjunto de dados. Integrado ao .Net via TensorFlowSharp.
O gráfico de cálculo para análise de palavras no DeepMorphy consiste em 11 “sub-redes”:
O problema de mudar a forma das palavras é resolvido por uma rede 1 seq2seq.
O treinamento é realizado sequencialmente, primeiro as redes são treinadas por categoria (a ordem não importa). A seguir, são treinadas a classificação principal por tags, a lematização e uma rede para alteração da forma das palavras. O treinamento foi realizado em 3 GPUs Titan X. As métricas de desempenho da rede no conjunto de dados de teste da versão mais recente podem ser visualizadas aqui.
DeepMorphy for .NET é uma biblioteca .Net Standard 2.0. As únicas dependências são a biblioteca TensorflowSharp (a rede neural é iniciada por meio dela).
A biblioteca é publicada em Nuget, por isso é mais fácil de instalar através dela.
Se houver um gerenciador de pacotes:
Install-Package DeepMorphy
Se o projeto suportar PackageReference:
<PackageReference Include="DeepMorphy"/>
Se alguém quiser construir a partir de fontes, então as fontes C# estão aqui. Rider é utilizado para desenvolvimento (tudo deve ser montado em estúdio sem problemas).
Todas as ações são realizadas através do objeto da classe MorphAnalyzer:
var morph = new MorphAnalyzer ( ) ;
Idealmente, é melhor usá-lo como um singleton ao criar um objeto, gastando algum tempo carregando dicionários e a rede; Tópico seguro. Ao criar, você pode passar os seguintes parâmetros para o construtor:
Para análise, é utilizado o método Parse (leva como entrada um IEnumerable com palavras para análise, retorna um IEnumerable com o resultado da análise).
var results = morph . Parse ( new string [ ]
{
"королёвские" ,
"тысячу" ,
"миллионных" ,
"красотка" ,
"1-ый"
} ) . ToArray ( ) ;
var morphInfo = results [ 0 ] ;
A lista de categorias gramaticais suportadas, gramas e suas chaves está aqui. Se você precisar descobrir a combinação mais provável de gramas (tag), precisará usar a propriedade BestTag do objeto MorphInfo.
// выводим лучшую комбинацию граммем для слова
Console . WriteLine ( morphInfo . BestTag ) ;
Com base na própria palavra, nem sempre é possível determinar de forma inequívoca o significado de suas categorias gramaticais (ver homônimos), portanto, DeepMorphy permite visualizar as principais tags de uma determinada palavra (propriedade Tags).
// выводим все теги для слова + их вероятность
foreach ( var tag in morphInfo . Tags )
Console . WriteLine ( $ " { tag } : { tag . Power } " ) ;
Existe uma combinação de gramas em alguma das tags:
// есть ли в каком-нибудь из тегов прилагательные единственного числа
morphInfo . HasCombination ( "прил" , "ед" ) ;
Existe uma combinação de gramas na tag mais provável:
// ясляется ли лучший тег прилагательным единственного числа
morphInfo . BestTag . Has ( "прил" , "ед" ) ;
Recuperando categorias gramaticais específicas da melhor tag:
// выводит часть речи лучшего тега и число
Console . WriteLine ( morphInfo . BestTag [ "чр" ] ) ;
Console . WriteLine ( morphInfo . BestTag [ "число" ] ) ;
As tags são usadas quando você precisa de informações sobre várias categorias gramaticais de uma só vez (por exemplo, classe gramatical e número). Se você estiver interessado apenas em uma categoria, poderá usar a interface para as probabilidades dos significados das categorias gramaticais dos objetos MorphInfo.
// выводит самую вероятную часть речи
Console . WriteLine ( morphInfo [ "чр" ] . BestGramKey ) ;
Você também pode obter a distribuição de probabilidade por categoria gramatical:
// выводит распределение вероятностей для падежа
foreach ( var gram in morphInfo [ "падеж" ] . Grams )
{
Console . WriteLine ( $ " { gram . Key } : { gram . Power } " ) ;
}
Se, junto com a análise morfológica, for necessário obter lemas de palavras, então o analisador deve ser criado da seguinte forma:
var morph = new MorphAnalyzer ( withLemmatization : true ) ;
Lemas podem ser obtidos em tags de palavras:
Console . WriteLine ( morphInfo . BestTag . Lemma ) ;
Verificando se uma determinada palavra tem um lema:
morphInfo . HasLemma ( "королевский" ) ;
O método CanBeSameLexeme pode ser usado para encontrar palavras de um único lexema:
// выводим все слова, которые могут быть формой слова королевский
var words = new string [ ]
{
"королевский" ,
"королевские" ,
"корабли" ,
"пересказывают" ,
"королевского"
} ;
var results = morph . Parse ( words ) . ToArray ( ) ;
var mainWord = results [ 0 ] ;
foreach ( var morphInfo in results )
{
if ( mainWord . CanBeSameLexeme ( morphInfo ) )
Console . WriteLine ( morphInfo . Text ) ;
}
Se você precisar apenas de lematização sem análise morfológica, precisará usar o método Lemmatize:
var tasks = new [ ]
{
new LemTask ( "синяя" , morph . TagHelper . CreateTag ( "прил" , gndr : "жен" , nmbr : "ед" , @case : "им" ) ) ,
new LemTask ( "гуляя" , morph . TagHelper . CreateTag ( "деепр" , tens : "наст" ) )
} ;
var lemmas = morph . Lemmatize ( tasks ) . ToArray ( ) ;
foreach ( var lemma in lemmas )
Console . WriteLine ( lemma ) ;
DeepMorphy pode alterar a forma de uma palavra dentro de um lexema. A lista de flexões suportadas está aqui; As palavras do dicionário só podem ser alteradas nos formulários disponíveis no dicionário. Para alterar a forma das palavras, é utilizado o método Inflect; ele recebe como entrada uma enumeração de objetos InflectTask (contém a palavra fonte, a tag da palavra fonte e a tag na qual a palavra deve ser colocada). A saída é uma enumeração com os formulários necessários (se o formulário não puder ser processado, será nulo).
var tasks = new [ ]
{
new InflectTask ( "синяя" ,
morph . TagHelper . CreateTag ( "прил" , gndr : "жен" , nmbr : "ед" , @case : "им" ) ,
morph . TagHelper . CreateTag ( "прил" , gndr : "муж" , nmbr : "ед" , @case : "им" ) ) ,
new InflectTask ( "гулять" ,
morph . TagHelper . CreateTag ( "инф_гл" ) ,
morph . TagHelper . CreateTag ( "деепр" , tens : "наст" ) )
} ;
var results = morph . Inflect ( tasks ) ;
foreach ( var result in results )
Console . WriteLine ( result ) ;
Também é possível obter todas as formas de uma palavra usando o método Lexeme (para palavras do dicionário ele retorna tudo do dicionário, para outras todas as formas das flexões suportadas).
var word = "лемматизировать" ;
var tag = m . TagHelper . CreateTag ( "инф_гл" ) ;
var results = m . Lexeme ( word , tag ) . ToArray ( ) ;
Uma das características do algoritmo é que ao alterar a forma ou gerar um lexema, a rede pode “inventar” uma forma inexistente (hipotética) da palavra, forma que não é utilizada na linguagem. Por exemplo, abaixo você encontra a palavra “correrá”, embora no momento ela não seja particularmente usada no idioma.
var tasks = new [ ]
{
new InflectTask ( "победить" ,
m . TagHelper . CreateTag ( "инф_гл" ) ,
m . TagHelper . CreateTag ( "гл" , nmbr : "ед" , tens : "буд" , pers : "1л" , mood : "изъяв" ) )
} ;
Console . WriteLine ( m . Inflect ( tasks ) . First ( ) ) ;