囲Pieの中出し





分配的セマンティックパイでの叙事詩の継続(およびファッショントレンドの追求)で、WebサービスをラピッドパイソンからプログレッシブGoに書き直すことにしました。 同時に、彼は「知的」部分全体を転送することを余儀なくされました(ニュートンの二項ではなく、良い)。 これを行うには、最初に予想したよりもはるかに簡単で快適であることが判明しました。 しかし、人生の蜂蜜構文のお祝いでは、軟膏のハエは完全ではありませんでした-私が見つけることができた最速の「ナンバークラッシャー」(gonumからのマット)は、pythonバンドルnumba + numpyにまだ劣っていました。



計画を実施するには、次のことが必要でした。





word2vecモデルをダウンロードする



ここではすべてが簡単です-ベクトルの関連する正規化とマップ(マップ)の形成を使用して、バイナリと辞書から辞書を読み取ります。単語はベクトルのインデックスです。 マッピングにより、ベクトルを単語ごとにすばやく引き出すことができます。 正規化により、コサインの近接度を計算する時間が節約されます。単語の比較はスカラー積になり、単語の「バッグ」と行列乗算の比較が減少します。



コード
type W2VModel struct { Words int Size int Vocab []string WordIdx map[string]int Vec [][]float32 } func (m *W2VModel) Load(fn string) { file, err := os.Open(fn) if err != nil { log.Fatal(err) } fmt.Fscanf(file, "%d", &m.Words) fmt.Fscanf(file, "%d", &m.Size) var ch string m.Vocab = make([]string, m.Words) m.Vec = make([][]float32, m.Words) m.WordIdx = make(map[string]int) for b := 0; b < m.Words; b++ { m.Vec[b] = make([]float32, m.Size) fmt.Fscanf(file, "%s%c", &m.Vocab[b], &ch) m.WordIdx[m.Vocab[b]] = b binary.Read(file, binary.LittleEndian, m.Vec[b]) length := 0.0 for _, v := range m.Vec[b] { length += float64(v * v) } length = math.Sqrt(length) for i, _ := range m.Vec[b] { m.Vec[b][i] /= float32(length) } } file.Close() }
      
      





「詩的」モデルを読む



ここではさらに簡単です-Pythonで事前に作成されたJSONファイルをGo構造とスライスで事前に読むことは簡単です。主なことは、フィールド名の大文字を忘れないことです。 そして、すべてをより速く計算できるように、レジから離れることなくバッグパイからマトリックスをスタンプします。



コード
 type PoemModel struct { Poems []string `json:"poems"` Bags [][]string `json:"bags"` W2V W2VModel Vectors [][][]float32 Matrices []mat.Matrix } func (pm *PoemModel) LoadJsonModel(fileName string) error { file, err := ioutil.ReadFile(fileName) if err != nil { return err } err = json.Unmarshal(file, pm) if err != nil { return err } return nil } func (pm *PoemModel) Matricize() { pm.Matrices = make([]mat.Matrix, len(pm.Bags)) for idx, bag := range pm.Bags { data, rows := pm.TokenVectorsData(bag) pm.Matrices[idx] = mat.NewDense(rows, pm.W2V.Size, data).T() } }
      
      





形態分析装置



世界には良い人がいないわけではありません-pymorphy2をGoに翻訳した良い人がいました。 確かに、Pythonパッケージマネージャーで形態辞書をインストールするために、ソースに2、3行を並べる必要がありました。それから、Pythonを介してそれらを検索することはアイデアです。 罪から、彼は辞書を(まっすぐなアナライザーと共に)彼のプロジェクトに投げました。



「知的」部分



トークナイザー-単語を通常の形式に変換し(見出し語化)、対応する文法接尾辞(NOUN、VERB、ADJなど)をそれらに追加し(word2vecモデル)、ストップワード(代名詞、前置詞、助詞)を削除します。



コード
 func (pm *PoemModel) TokenizeWords(words []string) []string { POS_TAGS := map[string]string { "NOUN": "_NOUN", "VERB": "_VERB", "INFN": "_VERB", "GRND": "_VERB", "PRTF": "_VERB", "PRTS": "_VERB", "ADJF": "_ADJ", "ADJS": "_ADJ", "ADVB": "_ADV", "PRED": "_ADP", } STOP_TAGS := map[string]bool {"PREP": true, "CONJ": true, "PRCL": true, "NPRO": true, "NUMR": true} result := make([]string, 0, len(words)) for _, w := range words { _, morphNorms, morphTags := morph.Parse(w) if len(morphNorms) == 0 { continue } suffixes := make(map[string]bool) // added suffixes for i, tags := range morphTags { norm := morphNorms[i] tag := strings.Split(tags, ",")[0] _, hasStopTag := STOP_TAGS[tag] if hasStopTag { break } suffix, hasPosTag := POS_TAGS[tag] _, hasSuffix := suffixes[suffix] if hasPosTag && ! hasSuffix { result = append(result, norm + suffix) suffixes[suffix] = true } } } return result }
      
      





意味的に「共鳴する」パティの検索は、クエリワードから形成されたベクトルのマトリックスに、モデルのロード時に作成されたパティのすべてのマトリックスを順次乗算することによって取得されます。 各積の結果(つまり、行列)は、乗算された行列の単語ベクトルの数で除算することによって合計され、正規化されます。結果の「共振」数(パイのインデックスに事前リンク)は降順でソートされ、最も上になります。



コード
 func (pm *PoemModel) SimilarPoemsMx(queryWords []string, topN int) []string { simPoems := make([]string, 0, topN) tokens := pm.TokenizeWords(queryWords) queryData, queryVecsN := pm.TokenVectorsData(tokens) if len(tokens) == 0 || topN <= 0 || queryVecsN == 0{ return simPoems } queryMx := mat.NewDense(queryVecsN, pm.W2V.Size, queryData) type PoemSimilarity struct { Idx int Sim float64 } sims := make([]PoemSimilarity, len(pm.Bags)) for idx, _ := range pm.Bags { var resMx mat.Dense bagMx := pm.Matrices[idx] _, poemVecsN := bagMx.Dims() resMx.Mul(queryMx, bagMx) sim := mat.Sum(&resMx) if poemVecsN > 0 { sim /= float64(poemVecsN + queryVecsN) } sims[idx].Idx = idx sims[idx].Sim = sim } sort.Slice(sims, func (i, j int) bool { return sims[i].Sim > sims[j].Sim }) for i := 0; i < topN; i ++ { simPoems = append(simPoems, pm.Poems[sims[i].Idx]) } return simPoems }
      
      





Webサービス



Webパーツを実装するために、 gin-gonicパッケージ (ルーター、静的、CORS)をすべて使用しました。



Githubプロジェクト



試すサービス



All Articles