[python3] 日本語⇄英語の翻訳を作りたい

機械翻訳とは、入力に対し最もらしい答えをレスポンスする

1. ルールベースの機械翻訳
原言語を構文解析し、文法構造を把握した後、辞書を用いて文節単位で目的言語へ翻訳して、最後に目的言語の文法へ翻訳した文字列を並び変える。

2. 統計的機械翻訳
原言語と目的言語の対話文から意味的な等価性、目的言語からその言語らしさを学習して確率モデルを作成し、作成したモデルから意味的な等価性と目的言語らしさの確率が最大となるような文を翻訳結果として出力する

– 翻訳確率
– 言語モデル

$ vagrant init ubuntu/focal64
vagrantfile

Vagrant.configure("2") do |config|

  config.vm.network "private_network", ip: "192.168.33.10"

  config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
    vb.customize ["modifyvm", :id, "--memory", "4096"]
  end

  if Vagrant.has_plugin?("vagrant-vbguest")
      config.vbguest.auto_update = false  
  end
end

$ vagrant up
$ vagrant ssh
$ sudo apt update

### Mosesのインストール
翻訳モデルと言語モデルから翻訳結果を出力するデコーダの役割をするMosesをインストールする

– パッケージインストール
$ sudo apt-get install build-essential git-core pkg-config automake libtool wget zlib1g-dev python-dev libbz2-dev
– Mosesのコンパイルに必要なboostのセットアップ
$ wget http://downloads.sourceforge.net/boost/boost_1_59_0.tar.bz2
$ tar jxvf boost_1_59_0.tar.bz2
$ cd boost_1_59_0
$ ./bootstrap.sh
$ ./b2 -j4 –prefix=$PWD –libdir=$PWD/lib64 –layout=system link=static install || echo FAILURE

### Mosesセットアップ
$ git clone https://github.com/moses-smt/mosesdecoder.git
$ cd mosesdecoder
$ ./bjam –with-boost=/home/vagrant/nlp/boost_1_59_0 -j4
You MUST do 3 things before sending to the mailing list:
1. Subscribe to the mailing list at http://mailman.mit.edu/mailman/listinfo/moses-support
2. Attach build.log.gz to your e-mail
3. Say what is the EXACT command you executed when you got the error
ERROR
ん????

[Python3] 歌詞をスクレイピングして頻出単語をwordcloudで表示

$ sudo pip3 install pandas

# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time

list_df = pd.DataFrame(columns=['歌詞'])

for page in range(1, 3):

	base_url = 'https://hogehoge'

	url = 'https://hogehoge/' + str(page) + '/'
	response = requests.get(url)
	soup = BeautifulSoup(response.text, 'lxml')
	links = soup.find_all('td', class_='side td1')
	for link in links:
		a = base_url + (link.a.get('href'))

		response = requests.get(a)
		soup = BeautifulSoup(response.text, 'lxml')
		song_lyrics = soup.find('div', itemprop='lyrics')
		song_lyric = song_lyrics.text
		song_lyric = song_lyric.replace('\n', '')
		time.sleep

		tmp_se = pd.DataFrame([song_lyric], index=list_df.columns).T
		list_df = list_df.append(tmp_se)

print(list_df)
list_df.to_csv('list.csv', mode='a', encoding='cp932')

### janomeによる形態素解析
$ sudo pip3 install janome

# -*- coding: utf-8 -*-
from janome.tokenizer import Tokenizer
import pandas as pd
import re

df_file = pd.read_csv('list.csv', encoding='cp932')

song_lyrics = df_file['歌詞'].tolist()

t = Tokenizer()

results = []

for s in song_lyrics:
	tokens = t.tokenize(s)

	r = []

	for tok in tokens:
		if tok.base_form == '*':
			word = tok.surface
		else:
			word = tok.base_form

		ps = tok.part_of_speech

		hinshi = ps.split(',')[0]

		if hinshi in ['名詞','形容詞','動詞', '副詞']:
			r.append(word)

	rl = (' '.join(r)).strip()
	results.append(rl)
	result = [i.replace('\u3000', '') for i in results]
	print(result)

text_file = 'wakati_list.txt'
with open(text_file, 'w', encoding='utf-8') as fp:
	fp.write("\n".join(result))

### wordcloud
$ sudo pip3 install wordcloud
https://www.google.com/get/noto/
Noto Sans CJK JPをダウンロードしてNotoSansMonoCJKjp-Regular.otfを使います。

# -*- coding: utf-8 -*-
from wordcloud import WordCloud

text_file = open('wakati_list.txt', encoding='utf-8')
text = text_file.read()

fpath = 'NotoSansMonoCJKjp-Regular.otf'

stop_words = ['そう', 'ない', 'いる', 'する', 'まま', 'よう', 'てる', 'なる', 'こと', 'もう', 'いい', 'ある', 'ゆく', 'れる', 'ん', 'の']

wordcloud = WordCloud(background_color='white',
	font_path=fpath, width=800, height=600, stopwords=set(stop_words)).generate(text)

wordcloud.to_file('./wordcloud.png')

$ python3 word_cloud.py

LunaSeaでやった場合

lunaseaは「夜」が多いなwww

なるほど、面白いなこれ。
応用としては、、、
エンジニアだと技術情報だけど、ファッション、旅行、スポーツなどでやりたい。特に旅行は万人受けするからなー

[Python3] fastTextとgensimで自然言語処理を実装する

Gensim: 自然言語処理ライブラリ、fastTextを実行できる、トピックモデルの作成、tf-idf、Word2Vecなど
$ sudo pip3 install gensim

### 分かち書きした日本語のテキストを用意
$ wget https://s3-ap-northeast-1.amazonaws.com/dev.tech-sketch.jp/chakki/public/ja.text8.zip
$ unzip ja.text8.zip
※small (100MB) text corpus from the wikipedia
https://github.com/Hironsan/ja.text8

$ which fasttext
$ /usr/local/bin/fasttext skipgram -input ja.text8 -output ja.text8.model

一体なんやこれは?????

$ ls
app.py ja.text8 ja.text8.model.bin ja.text8.model.vec ja.text8.zip

### 学習済みモデル
$ sudo pip3 install python-Levenshtein
$ less -S ja.text8.model.vec
$ python3

>>> from gensim.models import KeyedVectors
>>> word_vecs = KeyedVectors.load_word2vec_format(‘~/test/rss/ja.text8.model.vec’, binary=False)
>>> word_vecs.most_similar(positive=[‘公園’])
[(‘東公園’, 0.7657707929611206), (‘森林公園’, 0.7654288411140442), (‘園内’, 0.7647179961204529), (‘西公園’, 0.7584214210510254), (‘レクリエーション’, 0.7228037118911743), (‘緑地公園’, 0.7194845676422119), (‘遊歩道’, 0.7175000905990601), (‘芝公園’, 0.7167261242866516), (‘グチ’, 0.7141640186309814), (‘花瀬’, 0.7108176946640015)]

>>> word_vecs.most_similar(positive=[‘国王’, ‘女’], negative=[‘男’])
[(‘王妃’, 0.6794450879096985), (‘アルフォンソ’, 0.677681028842926), (‘王族’, 0.6705313324928284), (‘テオドラ’, 0.6641644239425659), (‘アフォンソ’, 0.6623624563217163), (‘エリザヴェータ’, 0.6613386273384094), (‘シャルマネセル’, 0.6583849787712097), (‘王’, 0.6572801470756531), (‘ナバラ’, 0.6571141481399536), (‘アブデュルハミト’, 0.6528143882751465)]
>>> word_vecs.most_similar(positive=[‘駅’], negative=[])
[(‘紀勢本線’, 0.829847514629364), (‘信越本線’, 0.8256024122238159), (‘南海本線’, 0.8238951563835144), (‘東上本線’, 0.8169854879379272), (‘羽越本線’, 0.8133241534233093), (‘本四備讃線’, 0.8125778436660767), (‘中央本線’, 0.8098829984664917), (‘総武本線’, 0.8089748024940491), (‘関西本線’, 0.8083009719848633), (‘日豊本線’, 0.8078861832618713)]

つまりKeyedVectorsでmost_similarで類語を検出したり、単語の計算ができる

>>> word_vecs.most_similar(positive=[‘イチロー’, ‘サッカー’], negative=[‘野球’])[(‘フェイエノールト’, 0.7010015845298767), (‘gk’, 0.6880401372909546), (‘ベンフィカ’, 0.6829041242599487), (‘アウストリア・ウィーン’, 0.6794724464416504), (‘コパ・デル・レイ’, 0.6772794127464294), (‘ガンバ’, 0.6750086545944214), (‘ゴールキーパー’, 0.6735791563987732), (‘ゴールイン’, 0.6722267866134644), (‘ネッツァー’, 0.6708939671516418), (‘ジュビロ’, 0.668694257736206)]
が、学習データによって精度に問題がある。

プロセスとしては、
1. 形態素分析
2. fasttext skipgram -input ja.text8 -output ja.text8.model で単語をベクトルに変更
3. KeyedVectorsで学習済み日本語モデルを読み込んで使用

重み付けとは要するに多数決の理論
機械学習だとどうしてもデータセットが適切か、データ量は十分か、果たしてそのモデルが優れているのか?など、品質を上げる為には自問自答が続く。
そして、ある課題に対し、どのモデルが最適かを提案するには、モデルの構造に関する知識が不可欠であり、特徴を整理しなければならない。
突き詰めると、前頭葉を中心とした人間の脳の機能を理解して、人間が行なっている判断に類するものをモデルに反映させる
文章を読むだけでは理解できない、実際に応用して初めて物になる。

言い換えが必要なシーンを考えるか。考えることが違うな。

[Python3] fastTextでカテゴリ別に分類したい

単語のベクトル化と文章分類は、fastTextのライブラリで実装する。

$ cat /etc/redhat-release
CentOS Linux release 8.3.2011

### fastTextの利用方法
Word representation learning(単語表現学習), Text classification(文章分類)

1.Word representation learning
-> 似ている単語の学習

2.Text classification
-> 分類された文章の学習

どちらも分かち書きした文章が必要になる。
固有表現に強い辞書「mecab-ipadic-NEologd」をインストールする

$ cd /usr/local/src
$ sudo git clone –depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
$ cd mecab-ipadic-neologd
$ ./bin/install-mecab-ipadic-neologd -n -y

### fastText install
$ cd /usr/local/src
$ sudo git clone https://github.com/facebookresearch/fastText.git
$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText

$ sudo mkdir build && cd build && sudo cmake ..
$ sudo make && sudo make install
$ which fasttext
/usr/local/bin/fasttext

$ cd /usr/local/src/fastText
$ sudo pip3 install .

$ wget https://github.com/livedoor/datasets/archive/master.zip
$ ls
$ unzip master.zip
$ cd datasets-master/
$ gzip -d ldgourmet.tar.gz
$ tar xvf ldgourmet.tar
$ ls
README.md categories.csv prefs.csv ratings.csv stations.csv
areas.csv ldgourmet.tar rating_votes.csv restaurants.csv

### 前処理 & データセットの作成
app.py

import csv
import MeCab
import neologdn
import re
import emoji

mecab = MeCab.Tagger('-Owakati -d /usr/lib64/mecab/dic/mecab-ipadic-neologd/')

with open('rating.csv') as f:
	reader = csv.reader(f)
	next(reader)
	for row in reader:
		label = "__label__{0}".format(row[3])

		text1 = neologdn.normalize(row[9])
		text2 = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+','', text1)
		text3 = ''.join(['' if c in emoji.UNICODE_EMOJI else c for c in text2])
		tmp = re.sub(r'(\d)([,.])(\d+)', r'\1\3', text3)
		text4 = re.sub(r'\d+', '0', tmp)

		tmp = re.sub(r'[!-/:-@[-`{-~]', r' ', text4)
		text5 = re.sub(u'[■-♯]', '	', tmp)

		text = mecab.parse(text5).rstrip('\n')
		print(label + " , " + text)

なんやこれ、前準備が厄介やな。。。。
どうすっかな、これ。。。

Pythonで自然言語処理(mecab)

$ python3 –version
Python 3.6.8
$ pip3 –version
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)

$ sudo pip3 install mecab-python3
$ sudo pip3 install unidic-lite

単語と単語を分けるのを分かち書きという
$ python3
>>> import MeCab
>>> wakati=MeCab.Tagger(“-Owakati”)
>>> sentence_wakati = wakati.parse(“私は今システム開発を行なっています”).split()
>>> print(sentence_wakati)
[‘私’, ‘は’, ‘今’, ‘システム’, ‘開発’, ‘を’, ‘行なっ’, ‘て’, ‘い’, ‘ます’]

ん?
“行なって” + “います” が正の様に思うが。。

自然言語処理ってことは、検索エンジン周りかチャットボット関連か。
もしくは文章の中から特定のキーワードを見つける e.g. 技術トレンドが入っている用語
RSSから、自然言語処理で内容を評価して、カテゴライズを自動化する など

何をやるかやな。

対話型操作の仕組み

### 対話型操作の例
– Siri(Apple)
– pepper(Softbank)
– Line りんな(Microsoft)
– チャットボット(IBM Watson, 富士通、OKWeb、ユーザローカル、SYNALIO、ドコモ、NTTコミュ、KDDI、SCSKなど)

-> NLP(自然言語処理)を活用して、対話システムを構築している

### 対話システムの歴史
– ELIZA(MIT, パターンマッチング)・・・決まった入力を仮定して、それに対して対応するため、人工無脳と言われる
– エキスパートシステム・・・ある特定分野に絞る
– Siri・・米国防高等研究計画局の人工知能プロジェクトとしてスタートしAppleに売却

### Retrieval model(Rules-Based)
ルールベースで対話を構築する
人工無脳に近い

### Generative model(general AI)
スクラッチから回答を自動生成するアプローチ
マルコフ過程を利用した単語から単語への状態遷移を予想して回答やニューラルネットワークのLSTMの利用などがある
機械翻訳と同じ技術が使われる

最近では、声のトーンから感情推定を行うなどの研究開発が盛んになってきている

とりあえず、順番にアプローチってところか?

wit.ai

https://wit.ai/

githubアカウントでログインします。

Test how your app understands a sentence
“Engineers tested da Vinci’s bridge design” と入れます。

「インテント」と「エンティティ」を学習させる
bridgeをtargetとするentityをcreateする
value for tested.

このエンティティはUserが自由に定義するようですね。
エンティティを定義して学習させる、という一連のフローは理解できました。

TF-IDF(Term Frequency-Inverse Document Frequency)

TFはTerm Frequency(単語頻度)
IDFはInverse Document Frequency(逆文章頻度): 単語を含む文章がどれだけの頻度で出現していないか、珍しさを表す指標

TFはN個の単語の内、n回表示だと、n/N で表すので、そのまま。
IDFはD個の文で単語tを含む文がd個ある時、 IDF = -log[10]d/D = log[10]D/d となる。指標が、[文章]単位に変わる。

TF-IDFはTFとIDFの積
単語の頻度と文章の頻度を掛ける

では実践してみましょう。

from math import log
import pandas as pd 

docs = [
	["ノンプレイヤーキャラクター", "プレイヤー","操作","キャラクター"],
	["プレイヤー","操作","キャラクター","プレイヤーキャラクター"],
	["NPC","PC"],
	["RPG用語","コンピューターゲーム","キャラクター","人間らしく","操作"],
	["NPC","ゲームマスター","プレイヤー","キャラクター","ゲーム","イベント","バランス","プレイヤー"]
]

words = list(set(w for doc in docs for w in doc))
words.sort()
print(words)

# TF-IDF
N = len(docs)

def tf(t, d):
	return d.count(t)/len(d)

def idf(t):
	df = 0
	for doc in docs:
		df += t in doc

	return log(N/df)+1

def tfidf(t,d):
	return tf(t,d)* idf(t)

# TF
result = []
for i in range(N):
	result.append([])
	d = docs[i]
	for j in range(len(words)):
		t = words[j]

		result[-1].append(tf(t,d))

tf_ = pd.DataFrame(result, columns=words)
print(tf_)

# IDF
result = []
for j in range(len(words)):
	t = words[j]
	result.append(idf(t))

idf_ = pd.DataFrame(result, index=words, columns=["IDF"])
print(idf_)

# TF-IDF
result = []
for i in range(N):
	result.append([])
	d = docs[i]
	for j in range(len(words)):
		t = words[j]

		result[-1].append(tfidf(t,d))

tfidf_ = pd.DataFrame(result, columns=words)
print(tfidf_)

[vagrant@localhost python]$ python app.py
[‘NPC’, ‘PC’, ‘RPG用語’, ‘イベント’, ‘キャラクター’, ‘ゲーム’, ‘ゲームマスター’, ‘コンピューターゲーム’, ‘ノンプレイヤーキャラクター’, ‘バランス’, ‘プレイヤー’, ‘プレイヤーキャラクター’, ‘人間らしく’, ‘操作’]
NPC PC RPG用語 イベント キャラクター … バランス プレイヤー プレイヤーキャラクター 人間らしく 操作
0 0.000 0.0 0.0 0.000 0.250 … 0.000 0.25 0.00 0.0 0.25
1 0.000 0.0 0.0 0.000 0.250 … 0.000 0.25 0.25 0.0 0.25
2 0.500 0.5 0.0 0.000 0.000 … 0.000 0.00 0.00 0.0 0.00
3 0.000 0.0 0.2 0.000 0.200 … 0.000 0.00 0.00 0.2 0.20
4 0.125 0.0 0.0 0.125 0.125 … 0.125 0.25 0.00 0.0 0.00

[5 rows x 14 columns]
IDF
NPC 1.916291
PC 2.609438
RPG用語 2.609438
イベント 2.609438
キャラクター 1.223144
ゲーム 2.609438
ゲームマスター 2.609438
コンピューターゲーム 2.609438
ノンプレイヤーキャラクター 2.609438
バランス 2.609438
プレイヤー 1.510826
プレイヤーキャラクター 2.609438
人間らしく 2.609438
操作 1.510826
NPC PC RPG用語 イベント … プレイヤー プレイヤーキャラクター 人間らしく 操作
0 0.000000 0.000000 0.000000 0.00000 … 0.377706 0.000000 0.000000 0.377706
1 0.000000 0.000000 0.000000 0.00000 … 0.377706 0.652359 0.000000 0.377706
2 0.958145 1.304719 0.000000 0.00000 … 0.000000 0.000000 0.000000 0.000000
3 0.000000 0.000000 0.521888 0.00000 … 0.000000 0.000000 0.521888 0.302165
4 0.239536 0.000000 0.000000 0.32618 … 0.377706 0.000000 0.000000 0.000000

[5 rows x 14 columns]


TFは頻度なので、0≦TF≦1になってますね。
IDFは、”プレイヤー”や”キャラクター”など、使用頻度の高い方が、値が小さくなってます。log[10]D/dなので、dの値が大きくなるほど、IDFは小さくなることがわかります。
そしてTF-IDFは、TF同様、文章ごとに値が表示されます。

あ、IDFは珍しいワードの方が値が大きくなるので、TF-IDFで各単語の重み付けをして特徴を示しているんですね。

このロジック考えたの誰だよ、すごいな。。。

fasttext

Word2Vecの延長線上として、Facebookが開発したのがfasttext
-> より精度の高い計算を高速に実行
-> 字面の近しい単語同士により意味のまとまりをもたせるという手法を提案

基本的なアルゴリズムはWord2Vecと一緒そうですね。。
毎回計算するのではなく、キャッシュ化して計算を高速化しているのでしょうか。

論文
Enriching Word Vectors with Subword Information
skip-gram model is to maximize the log-likelihood
TΣt=1 ΣceCt log[p](wc|wt)
where the context Ct is the set of indices of words surrounding wt

-> 自然言語処理の歴史やコミュニティの勉強をかなりしている
-> 論文読む予備知識がかなり必要
-> とは言え、論文も身近な存在

自然言語処理の論文って言うと、勝手に院卒エンジニアの専門領域って先入観があったけど、別に誰でも読めるしアクセスできるんだなー