1.文字認識
(1)形態素解析
形態素(morpheme)は、最小の要素。単語よりもさらに細かく分割されている。
形態素解析(Morphological Analysis)では、文章を、その最小の品詞に分ける。
JanomeというPython用の形態素解析器を使う。
❶Janomeインストール
Google colabの場合、まずは以下を実行する。1回だけでいい。
!pip install janome
❷形態素解析の実行
tokenize関数を使って単語に分割する。
tokenizeはトークン化する、という意味。
s(sentense)に入れた文字を解析する。
from janome.tokenizer import Tokenizer t = Tokenizer() s = '吾輩は猫である。名前はまだない。' for word in t.tokenize(s): print(word)
結果は以下である。
吾輩 名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ は 助詞,係助詞,*,*,*,*,は,ハ,ワ 猫 名詞,一般,*,*,*,*,猫,ネコ,ネコ で 助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ ある 助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル 。 記号,句点,*,*,*,*,。,。,。 名前 名詞,一般,*,*,*,*,名前,ナマエ,ナマエ は 助詞,係助詞,*,*,*,*,は,ハ,ワ まだ 副詞,助詞類接続,*,*,*,*,まだ,マダ,マダ ない 形容詞,自立,*,*,形容詞・アウオ段,基本形,ない,ナイ,ナイ 。 記号,句点,*,*,*,*,。,。,。
❸必要な要素だけ抜き出す
たとえば、以下にすると、単語と読みだけを表示する。
print(word.surface,word.reading)
結果はこんな感じ。
吾輩 ワガハイ は ハ 猫 ネコ で デ ある アル 。 。 名前 ナマエ は ハ まだ マダ ない ナイ 。 。
(2)テキスト解析
・たとえば、予測する際に、SNSの情報も加味したい。だが、テキストを機械学習はできないので、テキストをベクトル表現(数字)に変換する。
・その方法だが、まずはJanomeなどによる単語分割が必要。
・IDや記号の場合は、そのまま数字ではんく、one-hotベクトルも活用する。
・コサイン類似度で文字列の関連度を予測する。
■トピック分析
・tf-idf法で頻出単語を明らかにする。
・tf-idf法は、単に頻出単語だけで分析するわけではない。「私」「的」「こと」などのどの文書でも単語として頻出のものは対象にしない。
・出現回数が1回などのものは処理対処外とする。たとえば出現回数を1万回で切るなどすることで、学習効率を改善できるようにする。
■類似度分析
・Word2vec
https://qiita.com/yoppe/items/512c7c072d08c64afa7e
また、たとえば、ある文章があって、その中に、(政府、法律、国会)などの言葉が何回登場するかという値(5,10,2)などの数字データにすれば、その文章に対する、国会や政府との関連度合いを数字化することができる。Word2vecはそんなことができると思う。
■BERT
Googleが発表した汎用モデル。Word Embedding
(3)形態素解析を使い、ワードクラウドの生成
・いろいろなサイトを参考にさせていただいた。
・言葉のリストをa.csvとして、GoogleColabにアップロードしておく
janomeをインストール。1回だけでいいはず
!pip install janome
ここから
import sys import csv import collections if 'google.colab' in sys.modules: #フォントをインストール !apt-get -y install fonts-ipafont-gothic from janome.tokenizer import Tokenizer t = Tokenizer() #単語リストを作成する list=[] with open('text/a.csv') as file1: for data in file1: for word in t.tokenize(data): #part_of_speechには、品詞以外の言葉もあるので、カンマでスプリットした先頭だけを取得し、品詞のみにする if word.part_of_speech.split(',')[0] in ['名詞','形容詞','副詞','感動詞']: list.append(word.surface) #単語リストを表示 print(list) x = collections.Counter(list) %matplotlib inline from wordcloud import WordCloud import matplotlib.pyplot as plt result = WordCloud(background_color="white",font_path='/usr/share/fonts/truetype/fonts-japanese-gothic.ttf',width=800,height=640).generate_from_frequencies(x) fig = plt.figure(figsize=(12,8)) plt.imshow(result) plt.axis("off") fig.tight_layout() #ファイルに保存 plt.savefig('wordcloud.png')
ネットワークスペシャリスト試験の合格体験談でやってみると、こんな感じ。雰囲気はわかるが、イマイチな感じだ。
2.音声認識
・アナログ音は連続値なので、それを離散化してデジタル化する。具体的にはサンプリングして量子化する。
・拡張子wavは非圧縮。mp3は圧縮していて、非可逆。
・高い音は周波数が高い。音を1オクターブ上げると、周波数は2倍になる。
・amplitude(振幅)
・音量について
音量は相対的なもの。なぜなら同じ音源ファイルでも、再生する機械の音量を上げれば音が大きくなる。相対的な音の大きさを表すのがdB(デシベル)。具体的には20×log10が使われる。
人間が聞こえる最小音は20μPaとされている。
A特性やC特性などの基準をもとに、音(騒音)の大きさを図る。
・波は振幅、位相、周波数の要素がある。人間は、位相の情報は理解できない。
周波数が音の高さで、振幅が大きさと思って、とりあえずはいいだろう。
(1)言葉の整理
❶チャネル数
モノラルなら 1 、ステレオなら 2
ステレオの場合、イヤホンで両耳から聞こえる。
❷サンプリングレート(単位:Hz,=回/秒?)
1秒あたりのサンプリング回数。サンプリング=標本化と考えていいだろう。
情報処理試験を参考にすると、標本化定理(サンプリング定理)により、電話のアナログ周波数(4kHz)の少なくとも2倍で標本化する必要がある。4kHzというのは、1秒間に4k(=4000)回振動するとい言う意味である。よって、2倍の1秒間に8k(=8000)回標本化する。
人間の耳だと、最低16kHzは欲しいらしく、人間が聞こえる能力を考えると、48kHzであれば十分らしい。ちなみに、CDは44.1kHzと決まっている。mp3も44.1kHzが多い。
高い音は、高周波であるが、サンプリングレートが低いと、高い音が拾えなくなってしまう。
❸ビット深度 (サンプルサイズとも言う?) (単位:バイト or bit)
音声データの1サンプルあたりのサイズ。量子化のときに、どのサイズで量子化するか。
情報処理試験だと、「音声信号を8ビットでディジタル符号化」とあるので、1バイト。一般的には2バイト(16bit)が多いだろう。
2の16乗だと、65536階調。2の8乗だと256階調しかない。うまく説明できないが、誤差がノイズになって聞こえることになる。
❹フレーム
フレーム数=時間(秒)×サンプリングレート
※1フレーム当たりのデータサイズなどは考慮しない、単純なフレーム数だと思う。ただ、フレームという言葉が少し理解しにくい。パケットなんだろうけど。
❺ビットレート
1秒あたりのデータ量
ビットレート = サンプリングレート × ビット深度 × チャネル数(ステレオなら2)
(❻フレームレート(単位:fps))
よくあるテレビや動画は、1秒間に30フレーム(正しくは29.97)の表示回数。
画像のきめ細やかさがわかる。
音声と動画では考え方が別ではないかと思うので、要確認。
(2)波を書いてみる
❶正弦定理
正弦定理というのがあったと思うが、単純に、x軸に角度α、y軸にsinαを取る。
ちなみに、sin0=0, sin(π/2)=1, sin(π)=0, sin(2π)=0 である。
グラフを書いてみる。
import matplotlib.pyplot as plt import numpy as np x = np.arange(0,2*np.pi,0.1) #サンプル間隔を0.1に指定。なめらかな曲線に。 print(x) # ==>[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9・・・ plt.plot(x,np.sin(x)) plt.show()
❷周波数1、高さ1のグラフ
周波数が1ということは、1秒間で波を1回打つということ。また、波の高さは1とする。
先の正弦定理のグラフは、波長が2πである。なので、x軸を2πで割ればいい。このとき、サンプリングするxを2πで割ってしまうと、角度が変な値になってしまう。なので、プロットするx軸のxの値を2πで割る。
import matplotlib.pyplot as plt import numpy as np x = np.arange(0,2*np.pi,0.1) plt.plot(x/(2*np.pi),np.sin(x)) #x軸を2πで割る plt.show()
❸別の書き方
上の❷の書き方は、正しくないと思って、以下にしてみた。
import matplotlib.pyplot as plt import numpy as np x = np.arange(0,1,0.01) #x軸は、単純に0から1にした。サンプリング周期は、0.01なので、1秒間に100回(つまり100Hz) plt.plot(x,np.sin(x*2*np.pi)) plt.show()
❹周波数とサンプリングレートも加える
周波数s=5、サンプリングレートsam_rate=100とする。
import matplotlib.pyplot as plt import numpy as np s = 5 #単純に周波数を5Hzとする。つまり、1秒間に5回の波を打つ sam_rate=100 x = np.arange(0,1,1/sam_rate) plt.plot(x,np.sin(x*s*2*np.pi)) plt.show()
❺標本化定理の証明
サンプリングレートを変えてみる。標本化定理では、周波数の2倍が無いと、正しく取れないとあった。
sam_rateを変化させながら、グラフの変化をみてみよう。
import matplotlib.pyplot as plt import numpy as np s = 5 #単純に周波数を5Hzとする。つまり、1秒間に5回の波を打つ sam_rate=100 x = np.arange(0,1,1/sam_rate) plt.plot(x,np.sin(x*s*2*np.pi)) plt.show()
グラフの整形がうまくいっていないので、直す場合は以下を参照いただきたい。
https://openbook4.me/sections/1396
以下のように、サンプリングレートが下がると、グラフがかなり厳しい。正直、2倍(=10)だと少ない気がする。
(1)WAVEファイルの読み込み
waveモジュールを使う。wavファイルを読み込んでみよう。
import wave #waveモジュールをインポート wavfile = wave.open('music.wav', 'rb') #wavファイルの読み込み。rbはread(読み込み)モード。書込みはwbとする。
以下に書いたが、ファイルのオープンfile1 = open('file1.txt', 'r') などと同じで、最後に閉じる file1.close 必要がある。
https://python3.hatenadiary.com/entry/2020/10/10/082523#1%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%AA%E3%83%BC%E3%83%97%E3%83%B3%E3%81%A8%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%BA
(2)音声ファイルのパラメータ
いろいろな情報を取得することができる。
詳しくは以下
https://docs.python.org/ja/3/library/wave.html
print(wavfile.getnchannels()) #モノラルなら 1 、ステレオなら 2 print(wavfile.getsampwidth()) #ビット深度。音声データの1サンプルあたりのサイズ(バイト数) print(wavfile.getframerate()) #サンプリングレート。1秒あたりのサンプリング回数 print(wavfile.getnframes()) #フレーム数。サンプリングレート×時間 にもなると思う。 print(float(wavfile.getnframes())/ wavfile.getframerate()) # 時間=フレーム数/サンプリングレート print(wavfile.getnchannels() * wavfile.getsampwidth() * wavfile.getnframes()) # ファイルサイズ=フレーム数×ビット深度×チャネル数(モノラルなら1)
(3)実際に取り込む
もう少し深く進める
%matplotlib inline import wave import numpy as np import matplotlib.pyplot as plt #音声ファイルmusic.wavを開く wavfile = wave.open('music.wav', 'rb') #読み込んだデータをdataに入れる。wavfile.getnframes()はフレーム数なので、以下は全行を読み込むという意味 data = wavfile.readframes(wavfile.getnframes()) #バイナリデータなので、intに変換 data = np.frombuffer(data, dtype="int16")
どんな値が入っているのか、それが興味がある。
WAVファイルは、RIFF(RIFF waveform Audio Format)という形式らしい。
大量のデータだとメモリがエラーになるので、フレーム数を指定してみた data = wavfile.readframes(500)
%matplotlib inline import wave import numpy as np import matplotlib.pyplot as plt wavfile = wave.open('music.wav', 'rb') data = wavfile.readframes(500) data = np.frombuffer(data, dtype="int16") print(data)
すると、以下のように生データが見える。
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 -1 -1 0 0 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -3 -2 -2 -2 -2 -2 -3 -3 -2 -2 -3 -3 -3 -3 -2 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -4 -3 -3 -3 -4 -3 -3 -3 -3 -3 -3 -3 -4 -4 -4 -4 -4 -4]
(4)波のグラフを描いてみる
Q.なぜ塗りつぶされるのか。波にならないの?
なぜ上下に出力される?
A.周波数が音の高さで、振幅は音の大きさと考えていいだろう。
音は、振動板が波を打って、音がでる。外部から受けた音が振動板を揺らし、このとき大きな音は大きく揺らす。その揺れをデータとして取得する。
なので、揺れて、伸びたり縮んだりするので、プラスもゼロもマイナスの値もとる。だから、amplitude(振幅)はプラスもゼロもマイナスも必ず通るので、図にすると塗りつぶされているように見える。
では、手順を解説する。
❶(参考)音声ファイルの録音
Windows10ではできないが、Windows8の場合、標準のサウンドレコーダをCMDから実行することで、wavで録音できる。
こんな感じ。今回は私が録音した「あ」という言葉である。ファイル名はa.wavとした。
SoundRecorder /FILE a.wav
❷Google colabに音声ファイルをUPloadする
以下にも書いたが、音声ファイル(.wavファイル)をGoogle colabにUploadする。
https://python3.hatenadiary.com/entry/2020/12/02/115753
❸音波形を描く
前半はすでに記載したプログラムであるが、音声に関する知識がないと、少し理解が難しいと思う。
とりあえず、コピペすれば動くだろう。
%matplotlib inline import wave import numpy as np import matplotlib.pyplot as plt wavfile = wave.open('a.wav', 'rb') data = wavfile.readframes(wavfile.getnframes()) data = np.frombuffer(data, dtype="int16") sam_rate=wavfile.getframerate() #計算式は複雑であるが、8バイト×サンプルサイズだけ2の階乗をした値が、表現可能な階調で、その半分とする。 data = data / (2**(8 * wavfile.getsampwidth() ) / 2) x = np.arange(0, len(data)/sam_rate, 1.0/sam_rate) plt.xlabel("time") plt.ylabel("amplitude") plt.grid() plt.plot(x,data) plt.show()
以下が(私の)「あ」の声
参考までに、以下が「い」の声。開始タイミングがずれたが、その点は無視してほしい。
3.画像認識
(1)OpenCVを使った画像処理
Pythonでは、「OpenCV」という画像処理のライブラリが利用できる。
使い方はとても簡単。import cv2でインポートし、
cv2.imread()メソッドで画像を読み込む。
cv2.imwrite()で画像をファイルに保存
(2)モノクロ画像(黒と白)
255が白で、0が黒である。この2色だけ。
❶画像を読み込んで、出力
小さくて見えないだろうが、以下のカタカナの「ウ」という画像を作成した。photoshopにて、画像サイズは10px、10px
%matplotlib inline import matplotlib.pyplot as plt import cv2 gazou = cv2.imread('u.bmp',0) #0を指定することで、モノクロを指定。これを指定しないと、gazou.shapeが3次元の(10, 10,3)になってしまった。 plt.imshow(gazou, 'gray') #grayを指定しないと、黄色と紫になってしまう。 print('画像サイズ(高さ、幅、色)=', gazou.shape) #==> (10, 10) モノクロの場合は色は無し print(type(gazou)) #==><class 'numpy.ndarray'> print(gazou)
❷数字データから画像を出力
逆に、gazouに数字データを入れて、それを画像ファイルにすることも可能。
このとき、numpyのarrayなので、gazou = np.array([ という形で、カンマ区切りでデータを入れる。
一部だけであるが、以下のような感じ。
%matplotlib inline import matplotlib.pyplot as plt import numpy as np gazou = np.array([ [255,255,255,255,255,0,255,255,255,255], [255,255,255,255,255,0,255,255,255,255], [0,0,0,0,0,0,0,0,0,0]]) plt.imshow(gazou, 'gray') #grayを指定しないと、黄色と紫になってしまう。
(3)グレースケール(黒と白以外に、灰色がある)
255が白で、0が黒であるし、その間の灰色も数字で表される。8ビットなので0~255。
❶画像を読み込んで、出力
%matplotlib inline import matplotlib.pyplot as plt import cv2 gazou = cv2.imread('u2.bmp', 0) plt.imshow(gazou, 'gray') print('画像サイズ(高さ、幅、色)=', gazou.shape) print(type(gazou)) print(gazou[:1]) #1行目だけを表示
(4)カラー
以下の花を読み込んでみる。
❶表示してみよう
%matplotlib inline import matplotlib.pyplot as plt import cv2 gazou = cv2.imread('flower.jpg') gazou= cv2.cvtColor(gazou, cv2.COLOR_BGR2RGB) # そのままだと、BGRとなっていて、色がおかしい。RGBに変換。※なぜBGRになっているかは不明 plt.imshow(gazou) print('画像サイズ(高さ、幅、色)=', gazou.shape) #モノクロの場合は色は無し print(type(gazou)) print(gazou[:1])
❷カラー画像の加工
・色を抜いてみる。以下により、RとGをどちらも0にし、Bだけにする
gazou[:, :, (0, 1)] = 0
・色を逆にする。
255から引くと、ネガの画像になる。
gazou = np.uint8(255 * np.ones(gazou.shape) - gazou)
%matplotlib inline import matplotlib.pyplot as plt import cv2 gazou = cv2.imread('flower.jpg') gazou= cv2.cvtColor(gazou, cv2.COLOR_BGR2RGB) # そのままだと、BGRとなっていて、色がおかしい。RGBに変換。※なぜBGRになっているかは不明 gazou = np.uint8(255 * np.ones(gazou.shape) - gazou) plt.imshow(gazou) print('画像サイズ(高さ、幅、色)=', gazou.shape) print(type(gazou)) print(gazou[:1])
❸グレースケールにしてファイルに出力
cv2.imwrite('flower2.jpg', gazou)にて、ファイル名をflower2.jpgとして保存する。
%matplotlib inline import matplotlib.pyplot as plt import cv2 gazou = cv2.imread('flower.jpg') #グレースケールに変換。cv2.cvtColorを使い、変換する方法としてcv2.COLOR_RGB2GRAYを指定する。 gazou = cv2.cvtColor(gazou,cv2.COLOR_RGB2GRAY) plt.imshow(gazou, 'gray') print('画像サイズ(高さ、幅、色)=', gazou.shape) #==> (1835, 1672) なので、2色になっている。 print(type(gazou)) print(gazou[:5]) #ファイルに保存。すると、グレースケールのファイルが保存される。 cv2.imwrite('flower2.jpg', gazou)
4.高度な画像処理:顔認識
スマホやデジカメでも、顔の部分だけがフォーカスされる。これは、Viola-Jones法が使われる。ViolaさんとJonesさんが発見したからこのように言われる。
やり方は単純で、白と黒の領域を組み合わせたパターンと、顔が一致するかを確認する。顔であれば、目のあたりが黒く、その周りは白いなどの特徴がある。
ただ、そんな単純なやり方だから、精度はとても悪い。それを、数多くの方法で、パターンにマッチするかを判断して、精度を高める。アンサンブル学習(Ensemble Learning)というキーワードがあるはずだ。