チーム20E1

課題名

音声認識(SVM(サポートベクターマシン)、ロジスティック回帰、k-近傍法、決定木)

研究者名

3-15-19 佐藤優大
3-15-20 新堀和紀

概要

母音は含まれる周波数成分を見て、最も低い周波数のピークと2番目のピークのそれぞれの周波数を見ることで判別できるという。
そこで、フーリエ変換したデータを、scikit-learnというライブラリを用いてあ、い、う、え、お、という音を学習させることで母音の判定を行う。
こちらで用意した特定の人物の音声データ(あ、い、う、え、お、それぞれ10個ずつ)の75%を、様々な方法(SVM(サポートベクターマシン)、ロジスティック回帰、k-近傍法、決定木)で学習し、残りの未知のデータへの正解率がどのようになるかを実験する。
また、もう1人の音声データを学習結果に基づいて分類することで、個人に依らずに音声を判別できるようになったかを確認する。


実験に用いた実行環境、データセット、プログラミング言語、ライブラリモジュール

▼実行環境
Google Colaboratory
▼使用言語
python
▼使用モジュール
pydub(音声処理)
numpy(機械学習に必要)
pandas(データセットをこれで作成)
matplotlib(波形などを視覚的に見るために使用)
scikit-learn(学習に用いる)
▼データセット
被験者2人分の音声データを元にデータセットを作成した。
被験者のうち一人に、「あ」「い」「う」「え」「お」と、それぞれの母音のみを発音してもらったファイルを、各母音に対して10個ずつ作成した。
さらに、それを取り込んだものに、それがどの母音を発音したかを判別するラベルをつけてデータセットとした。
これをランダムに訓練データとテストデータに分けて使用した。なお、訓練データの割合は全体の75%である。
また、これとは別の被験者が「あ」「い」「う」「え」「お」と、それぞれの母音のみを発音してもらったファイルを、各母音に対して1個ずつ作成した。
こちらは最初の被験者で学習した結果が、他の人にも応用できる汎用的なものであるかを確認する実験に用いる。


ソースコード

チーム20D2を参考し、一部コードはそのまま使用させていただきました。
以下のコード、自前の音声ファイルと、上のgithub(参考元)へのリンク内にある関数Discrete_Fourier_Transform(sample)を用い、ファイルの読み込み部分を修正すれば実験を再現出来ると思います。
▼pip
pip install pydub

▼import,google driveへのアクセス
from pydub import AudioSegment
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from google.colab import drive
from sklearn.svm import LinearSVC
drive.mount('/content/drive')


▼データセットの作成と学習する関数の呼び出し
sound_list = []
tagList = []
for j in range(1,6):
for i in range(1,11):
   if j == 1:
     tagList.append('a')
     sound = AudioSegment.from_file("/content/drive/My Drive/DataSet/あ"+ str(i).zfill(2)+".m4a", "m4a")
   elif j == 2:
     tagList.append('i')
     sound = AudioSegment.from_file("/content/drive/My Drive/DataSet/い"+ str(i).zfill(2)+".m4a", "m4a")
   elif j == 3:
     tagList.append('u')
     sound = AudioSegment.from_file("/content/drive/My Drive/DataSet/う"+ str(i).zfill(2)+".m4a", "m4a")
   elif j == 4:
     tagList.append('e')
     sound = AudioSegment.from_file("/content/drive/My Drive/DataSet/え"+ str(i).zfill(2)+".m4a", "m4a")
   elif j == 5:
     tagList.append('o')
     sound = AudioSegment.from_file("/content/drive/My Drive/DataSet/お"+ str(i).zfill(2)+".m4a", "m4a")
   samples = np.array(sound.get_array_of_samples())
   sample = samples[::sound.channels]
   sound_list.append(sample)
plt.bar(['1','x','2x','3x','4x','5x','6x','7x','8x','9x'],Discrete_Fourier_Transform(sample),0.1)
plt.show()

coefficient_dft = [[],[],[],[],[],[],[],[],[],[]]
for sound_instance in sound_list:
dft = Discrete_Fourier_Transform(sound_instance)
 for j in range(0,10):
   coefficient_dft[j].append(dft[j])
df = pd.DataFrame({'tag' : tagList,
                 'data':coefficient_dft[0],
                  'data1':coefficient_dft[1],
                  'data2':coefficient_dft[2],
                  'data3':coefficient_dft[3],
                  'data4':coefficient_dft[4],
                  'data5':coefficient_dft[5],
                  'data6':coefficient_dft[6],
                  'data7':coefficient_dft[7],
                  'data8':coefficient_dft[8],
                  'data9':coefficient_dft[9]})
#データを直に見ることが出来るようにしてある。
print(df.head())

Y = df['tag']
X = df.drop('tag', axis=1)
X_train, X_test, y_train, y_test = train_test_split(X, Y, random_state=0)
#ここから先で機械学習を行うメソッドを呼び出す。例:SVM
m = SVM(X_train,y_train,X_test,y_test)
for i in range(1,6):
#ここから先では訓練に使用したデータの話者ではない人の音声を分類できるかの実験を行っている
 sound = AudioSegment.from_file("/content/drive/My Drive/DataSet/a1_"+ str(i)+".m4a", "m4a")
 samples = np.array(sound.get_array_of_samples())
 sample = samples[::sound.channels]
 dft = Discrete_Fourier_Transform(sample)
 print(dft)
 dftIn =  [dft]
 print(m.predict(dftIn))
 sound = AudioSegment.from_file("/content/drive/My Drive/DataSet/a1_"+ str(i)+".m4a", "m4a")
 samples = np.array(sound.get_array_of_samples())
 sample = samples[::sound.channels]
 dft = Discrete_Fourier_Transform(sample)
 print(dft)
 dftIn =  [dft]
 print(m.predict(dftIn))

▼サポートベクターマシン
def SVM(X_train,y_train,X_test,y_test):
  model = LinearSVC()
   model.fit(X_train, y_train)
   print('SVM')
   #正解率を算出。
   print("train score:",model.score(X_train,y_train))
   print("test score:",model.score(X_test,y_test))
   return model


▼ロジスティック回帰
def logistic(X_train,y_train,X_test,y_test):
  #引数で反復回数を指定できる。デフォルトではおそらく収束しない。
   model = LogisticRegression()
   model.fit(X_train, y_train)
   print('logistic')
   print("train score:",model.score(X_train,y_train))
   print("test score:",model.score(X_test,y_test))
   return model

▼k-近傍法
def kNN(X_train,y_train,X_test,y_test):
  #3個で多数決を行うように引数を指定
   model = KNeighborsClassifier(n_neighbors=3)
   model.fit(X_train, y_train)
   print('k-NN')
   print("train score:",model.score(X_train,y_train))
   print("test score:",model.score(X_test,y_test))
   return model

▼決定木 (木の深さはいろいろやってみた)
def decisionTree():
  #ここの引数で深さを指定できる
   model = DecisionTreeClassifier(max_depth=3)
   model.fit(X_train, y_train)
   print('decisionTree')
   print("train score:",model.score(X_train,y_train))
   print("test score:",model.score(X_test,y_test))
   return model

結果

▼SVM
train score: 0.5945945945945946
test score: 0.6153846153846154
他の話者の声に関して判別した結果
正答
[あいうえお]
実験結果
[ううううう]
▼ロジスティック回帰
▼反復回数100
train score: 1.0
test score: 0.9230769230769231
備考:結果は収束しなかった
正答
[あいうえお]
実験結果
[ううううう]
▼反復回数500
train score: 1.0
test score: 0.9230769230769231
備考:結果は収束しなかった
正答
[あいうえお]
実験結果
[うああああ]

▼反復回数100000
train score: 1.0
test score: 0.9230769230769231
正答
[あいうえお]
実験結果
[うああああ]

▼決定木
▼深さ3
train score: 0.7837837837837838
test score: 0.46153846153846156
正答
[あいうえお]
実験結果
[あああああ]

▼深さ10000
train score: 1.0
test score: 0.7692307692307693
正答
[あいうえお]
実験結果
[いいいいい]


▼k-近傍法
train score: 0.8378378378378378
test score: 0.5384615384615384
正答
[あいうえお]
実験結果
[あああああ]

考察

ロジスティック回帰は、正解率が高かったが、デフォルトの設定では収束しなかった。
そこで、設定を変更すると収束し、高い正解率を出した。
また、時間が無かったので調整は出来なかったものの、他の方法で正解率点に関してもパラメータ設定次第で改善する可能性が十分にある。
このため、DFT後のデータを学習することで、母音の判別を行うことは、特定の人物の発音に限定すれば出来ると考えられる。

一方で、他の人物の発音と比較すると全く当たらなかった点に関しては、声のそもそもの違いを拾って母音の判定に用いてしまっている事が主な原因と考えられる。
例えば、別の人物のどの母音であっても、ある1つの母音だと判定することが多い原因は、声の高さや、声質的に含まれる周波数成分の違いを、学習結果が母音の違いだと判断してしまった結果であると考えられる。さらに、声自体の大きさや雑音の影響なども考えられるので、そのあたりを前処理などでどうにかした上で、多くの人物の発声を学習しなければ、汎用的な音声認識は出来ないかもしれない。これに関しては、データの数を増やすか、精度の確認の方法を工夫することで、改善できるかもしれない。また、今回学習時に要素としたデータは1音声あたり10個であり、周波数ピークをうまく拾えていない可能性もあるので、ここを細かくするかFFTを用いれば良い結果が得られるかもしれない。

  • 最終更新:2020-11-23 20:38:33

このWIKIを編集するにはパスワード入力が必要です

認証パスワード