# マルチメディア2 ## 問題2-1 多クラス(2クラス以上)のサンプル(2次元以上とする)を,各クラスに対して設定した正規分布などに基づく乱数の発生により生成した後,一部を学習サンプル,残りをテストサンプルとし,学習サンプルを用いて学習した識別器を用いてテストサンプルを分類するプログラムを作成して下さい. ## 各クラスのサンプル生成方法の説明(課題2-1) numpyをもちいてガウス分布のランダム値を生成した。 ## 識別器学習方法の説明 ### 多クラスロジスティック回帰 $t$番目の学習データのラベルの1-of-K表現を$y^{(t)}$とする。 また,$t$番目のモデルの出力を$\hat{y}^{(t)}$とする。 多クラス交差エントロピーの誤差関数は $$L = -\sum_t \sum_c y_c^{(t)} \log{\hat{y}^{(t)}_ c}$$ となる。重み係数による微分は $$\frac{dL}{dw} = \bf x\cdot (\hat{y} - \phi)$$ となる。ここで$\phi$はソフトマックス関数の値である。 よって重み係数の更新は $$w = w - \rho \frac{dL}{dw} $$ となる。 <div style="page-break-before:always"></div> ### 単純パーセプトロン 損失関数は持たない。 予測クラスと実際のクラスを比較して異なっていた場合、以下の条件に従って重みを更新する。 クラス1と予測したがクラス2だった場合 $$w = w - \rho x$$ クラス2と予測したがクラス1だった場合 $$w = w + \rho x$$ ### knn KNN(K Nearest Neighbor)。クラス判別用の手法。 学習器は持たず、識別器のみで構成される。 学習データをベクトル空間上にプロットしておき、未知のデータが得られたら、 そこから距離が近い順に任意のK個を取得し、多数決でデータが属するクラスを推定する。 未知のテストデータと各学習データの距離には、ベクトルのノルム計算を用いた。 ## アルゴリズム(疑似コード表現、フローチャートなど) ### 多クラスロジスティック回帰 ``` class LogisticClassifier: 関数名 __init__ で引数名(low = 0.1, loop = 1000)の関数作成: クラス変数 low に引数lowを代入 クラス変数 loop に引数loopを代入 関数名 fitで引数名(features,labels) の関数作成: 変数 n_rows と n_cols に特徴量のshape値を代入 変数 n_class に labels のshape値の2つ目を代入 w0を含めて重み係数を初期化するため、変数 wvec に関数__init_weights(変数 n_cols に1を足したもの, 変数 n_class)を代入 変数 xvecs に変数 n_rowsの分1で初期化した配列と変数featuresを連結させた配列を代入 クラス変数 loopの回数の間: 変数 wvec に関数 __train(変数xvecs, 変数wvec, 変数labels) の値を代入 クラス変数 wvec_ に 変数wvecを代入 クラス変数 intercept_ に 変数wvecの0番目の値を代入 クラス変数 coef_ に 変数wvecの1番目から最後までの値を代入 w0,w1,w2の値をプリントする 処理を返す 関数名 predict で引数名(features, labels)の関数作成: 変数名 n_rows と n_cols に 引数 featuresのshape値を代入 変数 xvecs に変数 n_rowsの分1で初期化した配列と変数featuresを連結させた配列を代入 変数 Phi に 関数__softmax(変数 wvecs と wvec_ の内積) の値を代入 変数 class_label にPhiの行ごとの値が最大のインデックスを代入する 変数 ypre に変数wvecsを行列として0で初期化した値を代入する ypreの行の数を変数 i に代入してループ: 変数 ypreのi行目 変数class_labelのi番目の値列目に1を代入する まず、変数ypreと変数labelsの配列同しを比較しboolean配列に変更する。そのまま行ごとに全てTrueであればTrueを、1つでもFalseがあればFalseを返すものの配列を生成し変数accuracyに代入する。 変数labelsのshape値の2つ目値を1つずつiに代入しループ: 変数indexに変数labelsのi+1番目の値が1であればTrueを違っていればFalseを代入 正答率とかをプリントする 処理を返す 関数名__init_weightsで引数(n_features, n_class)の関数作成: 変数n_featuresを行数とn_classを列数として1で初期化した行列を返す 関数名__trainで引数(xvecs, wvec, labels)の関数作成: 変数dwvecに関数__grad_loss(変数xvecs, 変数wvec, 変数labels)の値を代入 変数wvecに自身から(クラス変数lowに変数dwvecをかけたもの)を引いたものを代入 変数wvecを返す 関数名__softmaxで引数(z)の関数作成: # np.sum(np.exp(z), axis=1)は各行のsum値を横ベクトルで返してくれるので縦ベクトルにする ソフトマックス関数に変数zを代入したものを返す 関数名__grad_lossで引数(xvecs, wvec, labels)の関数作成: 変数zに変数xvecsとwvecの内積をとって代入 関数__softmax(変数z)を代入したのち小数点以下5つまで取得し変数Phiに代入 変数dwvecに変数xvecsと(変数labelsから変数Phiをひいたもの)の内積をとってマイナスをかけて代入する 変数dwvecを返す ``` ### 単純パーセプトロン 多クラス拡張 単純パーセプトロン ``` class Classifier: 関数名 __init__ で引数名(low = 0.1, loop = 1000)の関数作成: クラス変数 low に引数lowを代入 クラス変数 loop に引数loopを代入 関数名 fitで引数名(features,labels) の関数作成: 変数 n_rows と n_cols に特徴量のshape値を代入 変数 n_class に labels のshape値の2つ目を代入 変数labelsに引数labelsの値を縦行列にして代入 labels = labels.values.reshape(-1,) 変数is_cls1_listに変数labelsで1と等しい部分をTrue,違っていればFalseにするboolean配列に変換して代入 w0を含めて重み係数を初期化するため、変数 wvec に関数__init_weights(変数 n_cols に1を足したもの, 変数 n_class)を代入 変数 xvecs に変数 n_rowsの分1で初期化した配列と変数featuresを連結させた配列を代入 クラス変数 loopの回数の間: 変数xvecsと変数is_cls1_listの値を1つずつxvecとis_cls1に代入しながらループ: 変数 wvec に関数 __train(変数wvec, 変数xvec, 変数is_cls1) の値を代入 クラス変数 wvec_ に 変数wvecを代入 クラス変数 intercept_ に 変数wvecの0番目の値を代入 クラス変数 coef_ に 変数wvecの1番目から最後までの値を代入 w0,w1,w2の値をプリントする 処理を返す 関数名 predict で引数名(x, y)の関数作成: 変数yに引数yをnumpy配列にして代入 変数xvecsに変数xのshape値1番目の値分1で初期化したものと変数xを連結したものを代入 変数wvecにクラス変数intercept_とクラス変数coef_を連結したものを代入 変数ypreを変数yの行列分1で初期化する 変数xのshape値の1番目の値を変数rowに代入してループ: if 変数wvecと変数xvecsのrow行目の値の内積が0以下である: 変数ypreのrow番目の値に2を代入 クラス1とクラス2の正答率とかプリント 処理を返す 関数名__init_weightsで引数(num_x)の関数作成: 変数num_xの数だけ0.5の値をもつ配列を返す 関数名__trainで引数(wvecs, xvec, is_cls1)の関数作成: if 変数wvecと変数xvecの内積が0より大きい: if 変数is_cls1がFalseである: 変数wvecに自身から(クラス変数lowとxvecをかけたもの)を引いた値を代入 else: if 変数is_cls1がTrue: 変数wvecに自身から(クラス変数lowとxvecをかけたもの)を足した値を代入 変数wvecを返す ``` 多クラス拡張 ``` 関数名 fitで引数名(features,labels, clsnum) の関数作成: 途中まで一緒 変数clsnumの数まで順に変数iに代入してループ: 変数 is_cls_list に(labelsと変数 i+1がいっちするかどうかのboolean配列)を代入 w0を含めて重み係数を初期化 x0 = 1を追加 xvecs = np.c_[np.ones(n_rows), features] クラス変数 loopの回数の間: 変数xvecsと変数is_cls1_listの値を1つずつxvecとis_cls1に代入しながらループ: 変数 wvec に関数 __train(変数wvec, 変数xvec, 変数is_cls1) の値を代入 クラス変数の配列の最後に wvec_ に 変数wvecを代入 クラス変数の配列の最後に intercept_ に 変数wvecの0番目の値を代入 クラス変数の最後に coef_ に 変数wvecの1番目から最後までの値を代入 関数名 predict で引数名(x_test, y_test, clsnum)の関数作成: 途中まで一緒 clsnumの数だけfに代入してループ: 変数wvecに各クラスごとのintercept_とcoef_を連結し代入 サンプル数分ループしてwvecとxvecの内積が0以下であればypreのf番目に0を代入 ypreはサンプル数を行、クラス数を列にもつone-hot表現のようになっている。 ypreで1つのみの1をもつ行(サンプル)はそのクラスとして確定 クラスとして確定した集団の平均値を計算する ypreで複数の1をもつ行(サンプル)がある場合、各ラスの平均値に一番近いものにクラス分類する。 return ``` ### knn 多クラス対応 ``` class KNeighbors(): 関数名 __init__ で引数なしの関数作成: クラス変数 n_neighbors を作成 クラス変数 x_train を作成 クラス変数 y_train を作成 関数名 fit で引数名(x_train, y_train, n_neighbors)の関数作成: クラス変数 x_train に学習データの座標情報を代入 クラス変数 y_train に学習データのクラス情報を代入 クラス変数 n_neighbors に近傍数kを代入 関数名 predict で引数名(x_test, y_test)の関数作成: 変数 y にテストデータのクラス情報である引数 y_test をnumpy配列で代入 変数 y_pre に 変数 y と同じサイズの0配列を代入 変数 y_tmp に空の配列を代入 変数 i を用いて引数 x_test の行数だけ繰り返し: 与えられた i 番目のテストデータ x_test[i] と学習データ全ての         ベクトルを求め、ノルムを計算し変数 distances に代入    変数 distances と クラス変数 x_train は行番号で対応している 変数 distances のうち、距離を昇順に並べた際のデータの元のインデックスを         変数 neighbors_index にk個だけ代入 変数 m を用いて変数 neighbors_index の行数だけ繰り返し: 変数 y_tmp に、各インデックスに属するデータのクラス情報を代入 例:y_tmp = [1, 2, 2, 2, 1, 1, 2, 1, 2,...](2クラスの場合) 変数 y_tmp にあるクラスデータのうち、最頻値を予測クラスとして変数 y_pre に代入 変数 y_tmp をリセットして次のテストデータに備える 変数 y_pre と y_test の値を比べることでk近傍数に応じた各クラスの正答率を表示 ``` ## 工夫点 ### 多クラスロジスティック回帰 多クラス拡張にあたって、ソフトマックス関数を用いた。またexpの計算でfloat型の数字を超えてしまうのでデータを標準化したのちに計算をした。 ### 単純パーセプトロン 特になし。 ### knn 前回の課題でpythonのfor計算がかなり遅いものだということを知り、テストデータ×学習データという計算を行列計算を用いることで計算量を抑えた。 データ間の距離をソートする際にあとで参照しやすいようにインデックスだけ持ってくる関数を発見した。先人たちの素晴らしい知恵を適切にお借りするという工夫を凝らした。 ## 実験結果と考察 ### 多クラスロジスティック回帰 #### 2クラス分類 サンプルについて ``` クラス1(青) 平均:100 偏差:10 ずれ:なし クラス2(橙) 平均:120 偏差:10 ずれ:なし ``` ![](https://i.imgur.com/ny2SE1u.png) ロジスティック回帰のソフトマックス関数が容易にfloat型の最大を超えてしまうのでデータに標準化をかけて分類器にかけた。学習の結果は以下の通り。 ![](https://i.imgur.com/OQBMgmK.png) 学習時間: 0.9491832256317139s **正答率** |クラス|正答率| |---|---| |class 1(青)|194/207(94%)| |class 2(橙)|179/193(93%)| #### 5クラス分類 サンプルについて ``` クラス1(青) 平均:100 偏差:10 ずれ:なし クラス2(橙) 平均:120 偏差:10 ずれ:なし クラス3(緑) 平均:140 偏差:10 ずれ:なし クラス4(赤) 平均:100 偏差:10 ずれ:横軸方向に40 クラス5(紫) 平均:100 偏差:10 ずれ:縦軸方向に40 ``` ![](https://i.imgur.com/onyRtHB.png) ロジスティック回帰のソフトマックス関数が容易にfloat型の最大を超えてしまうのでデータに標準化をかけて分類器にかけた。学習の結果は以下の通り。 ![](https://i.imgur.com/yTTN44P.png) 学習経過時間: 1.2094619274139404s **正答率** |クラス|正答率| |---|---| |class 1(青)|204/211(97%)| |class 2(橙)|31/209(15%)| |class 3(緑)| 198/202(98%)| |class 4(赤)| 175/188(93%)| |class 5(紫)| 183/190(96%)| ### 単純パーセプトロン #### 2クラス分類 サンプルについて ``` クラス1(青) 平均:100 偏差:10 ずれ:なし クラス2(橙) 平均:120 偏差:10 ずれ:なし ``` ![](https://i.imgur.com/XCDPHxA.png) 学習結果は以下の通り ![](https://i.imgur.com/Ez1onW6.png) 学習経過時間: 4.711416721343994s **正答率** |クラス|正答率| |---|---| |class 1(青)| 207/207(100%)| |class 2(橙)| 193/193(100%)| #### 5クラス分類 サンプルについて ``` クラス1(青) 平均:100 偏差:10 ずれ:なし クラス2(橙) 平均:120 偏差:10 ずれ:なし クラス3(緑) 平均:140 偏差:10 ずれ:なし クラス4(赤) 平均:100 偏差:10 ずれ:横軸方向に40 クラス5(紫) 平均:100 偏差:10 ずれ:縦軸方向に40 ``` ![](https://i.imgur.com/B1pHdOc.png) 学習の結果は以下の通り ![](https://i.imgur.com/ocpsef7.png) 学習経過時間: 32.375829219818115s **正答率** |クラス|正答率| |---|---| |class 1(青)| 209/211(99%)| |class 2(橙)| 3/209(1%)| |class 3(緑)| 186/202(92%)| |class 4(赤)| 154/188(81%)| |class 5(紫)| 0/190(0%)| ### knn サンプル作成クラスで平均、標準偏差を指定して正規分布に従うランダム数を1000個作成した。 このうち、学習データは800個、テストデータは200個とした。 このサンプルを2~5つ用いることで,クラス分類器の性能を検証し、結果の最後に考察を述べた。 性能評価の基準として、kを任意に変化させた時の各クラスにおける正答率、テスト時間を用いた。 kの値は固定値として1,11,101の3つ,各実験ごとのデータ数の半分,データ数-1とした。 以下は今回用いた5クラスのパラメータおよび散布図における色一覧である。 散布図を見る際はこちらを参照されたし。 ``` クラス1(青) 平均:100 偏差:10 ずれ:なし クラス2(橙) 平均:120 偏差:10 ずれ:なし クラス3(緑) 平均:140 偏差:10 ずれ:なし クラス4(赤) 平均:100 偏差:10 ずれ:横軸方向に40 クラス5(紫) 平均:100 偏差:10 ずれ:縦軸方向に40 ``` 〜2クラス〜 以下の図はクラス1~2までの散布図である。 ![](https://i.imgur.com/6JGpcnC.png) 総学習データ:1600個/総テストデータ:400個 テストデータ(クラス1:207個/クラス2:193個) |k= | 1| 11| 101|201|399| | --------: | --------: | --------: | --------: | --------: | --------: | |クラス1(%) |86.9|89.8|92.2|93.7|93.7| |クラス2(%) |89.1|94.3|93.2|93.2|92.7| |時間(s) |4.20|4.50|4.87|4.23|4.34| 〜3クラス〜 以下の図はクラス1~3までの散布図である。 ![](https://i.imgur.com/sIkJSK6.png) 総学習データ:2400個/総テストデータ:600個 テストデータ(クラス1:181個/クラス2:206個/クラス3:213個) |k= | 1| 11| 101|301|599| | --------: | --------: | --------: | --------: | --------: | --------: | |クラス1(%) |88.9|92.2|91.7|93.9|93.9| |クラス2(%) |76.2|83.9|85.4|84.4|84.4| |クラス3(%) |88.2|92.2|91.0|91.0|91.0| |時間(s) |11.4|9.48|8.98|9.14|10.2| 〜4クラス〜 以下の図はクラス1~4までの散布図である。 ![](https://i.imgur.com/zjs6kD9.png) 総学習データ:3200個/総テストデータ:800個 テストデータ(クラス1:199個/クラス2:195個/クラス3:205個/クラス4:201個) |k= | 1| 11| 101|401|799| | --------: | --------: | --------: | --------: | --------: | --------: | |クラス1(%) |86.9|93.9|91.9|92.4|92.4| |クラス2(%) |66.6|76.9|76.4|76.9|76.9| |クラス3(%) |90.2|94.1|93.1|92.1|92.1| |クラス4(%) |87.0|93.0|93.0|92.5|92.5| |時間(s) |15.9|16.6|16.5|17.7|17.0| 〜5クラス〜 以下の図はクラス1~2までの散布図である。 ![](https://i.imgur.com/d4P5JIL.png) 総学習データ:4000個/総テストデータ:1000個 テストデータ(クラス1:211個/クラス2:209個/クラス3:202個/クラス4:188個/クラス5:190個) |k= | 1| 11| 101|501|999| | --------: | --------: | --------: | --------: | --------: | --------: | |クラス1(%) |84.8|91.4|92.8|92.4|92.8| |クラス2(%) |66.5|72.7|73.6|74.1|74.6| |クラス3(%) |84.6|92.5|92.5|92.5|92.5| |クラス4(%) |83.5|88.2|88.2|88.8|89.3| |クラス5(%) |84.7|92.6|92.6|91.0|91.0| |時間(s) |25.4|26.9|26.9|28.4|27.4|  検証する前は、同じ分類の際にはkの値を増やせば計算時間が伸びるとともに正答率が上がるなどと思っていたが、実際近傍数による計算時間の変化はあまり見られなかった。5つ目のkに関しては学習データをほぼ全て参照するというある種嫌がらせのような数を採用したが、プログラムには効かなかったようだ。このことは、行列計算を採用していることが大きく影響を与えていると考えられる。もちろん分類するクラスの数、つまり学習データやテストデータを増やせば時間は増えるが、至極当然のことであるといえよう。  正答率に関しては、近傍数がふえるごとに伸びていくものだと考えていたが、1の時と全データ数の時とを比べた際、大差がついたかというと、そうはならなかった。つまり、無理に沢山の学習データを見なくとも、ある程度の性能は得られるということになる。101あたりがちょうど良いと考えたが、近傍数を変えても計算時間に影響しない分深く考える必要はなさそうである。  全体の性能評価としては、クラスが増えるにつれて計算時間は伸びたが、正答率に関しては申し分ない結果が出ているといえる。ただし、自クラスの学習データと他クラスの学習データとの重なりが多いクラスの正答率は8割を切ることがわかった。これは近傍数を増やしても改善はされないため、分類させたいクラス同士の座標関係によっては不向きな手法であると考えられる。 --- ## 問題2-2 課題2-1で作成したプログラムを応用し, 数字0~9の学習用画像を用いて,手書き文字(モノクロ画像)を認識する識別器を作成し, 手書き文字を複数含む画像から各数字を検出するプログラムを作成して下さい. ## 識別器学習方法の説明 まず、file_maker.ipynbで約60000枚の学習用画像のグレースケール画像としての値をとり、28*28のデータを1*784に変形した後、その画像の数字とともにmnist.pklというファイルで保存した。 その後、mnist.ipynbで保存したファイルを読み込む。ここで学習と検出を行った。学習はニューラルネットワークを利用し、入力が画像のpixelを一行に並べたものとし、入力層(第0層)は784個、中間層(第1層)は100個、出力層(第2層)は10個という構成になっている。1,2層からはバイアスも次の層に入力される。0から1層ではシグモイド関数、1から2層ではソフトマックス関数を採用した。また、誤差逆伝播法を用い、二乗和誤差を求め、SGDで重みやバイアスを更新した。また、バッチ処理により、一度に200の画像をランダムにとってきて処理し、また、約60000の画像を10周した。 ## 数字の検出方法の説明(課題2-2) 数字の検出にはラン解析を用い、周囲8pixelで検出し、ラベリングした。そのそれぞれのラベルで最小のx,yと最大のx,yから中心のx,yを求め、そこを中心とした28*28の範囲を取り出した。 ## アルゴリズムの概要、考え方のポイント、工夫点 アルゴリズムの概要は上に示した。 学習の速度を早くしようと考え、あらかじめ全画像データを格納したファイルを作り、バッチ処理を取り入れ、高速化を図った。 ラン解析を取り入れることで全探索に比べ、探索時間を減らた。ラベルごとの中心をとることでラベルされたものがすべて入ると考えた。 ## アルゴリズム(疑似コード表現、フローチャートなど) ### 学習部 ``` class Classification: 関数名 __init__ で引数名(input_size = 28*28, hidden1_size = 100, output_size = 10, weight_init_std = 0.01)の関数作成: クラス内のlood関数を呼び出す # 重み関数などを格納するdict paramsの空辞書を作成 params内のw1の初期値を784*100のランダム行列で作成 params内のb1の初期値を長さ100のゼロ行列で作成 params内のw2の初期値を100*10のランダム行列で作成 params内のb2の初期値を長さ10のゼロ行列で作成 関数名 trainで引数名(batch_size=200, n_epoch=10,leaning_rate = 0.0001) の関数作成: datlenにロードしたデータから学習用画像の数を代入 変数n_epochの値までnに代入してループ:# データセットを何周するか batch_maskにdatlenまででindexの値をランダムに並べたものを代入# 一回のバッチでデータのどこをとってくるのかランダムに並べ替え datlen/batch_sizeの商の値までbに代入してループ:# バッチ処理 bのループ内でのバッチ処理のための画像をbatch_sizeの分だけbatch_imgに代入 batch_imgの行に対応した数字の結果をbatch_labelに代入 gradsに引数を(batch_img, batch_label)としたクラス内のgradient関数の返り値を代入 ('w1','b1','w2','b2')を順にkeyに代入してループ: paramsのkeyから leaning_rateをかけたgradsのkeyを減算 n_epochの値が10までと最後から5つ前までの条件: n_epochと正答率をprint 処理を返す 関数名 predict で引数名(batchdat)の関数作成:# imgdataからlabelを予測 w1,w2にparamsから重みを代入 b1,b2にparamsからバイアスを代入 引数batchdatをクラス内変数に a1にbatchdatとw1の内積+b1を代入 z1にsigmoid関数の引数にa1を入れた時の返り値を代入 a1にz2とw2の内積+b1を代入 softmax関数の引数にa1を入れた時の値を返り値にして処理を返す 関数名 gradientで引数(x, t)を代入:# 勾配 Lにクラスろ×loss関数に引数(x, t)を与えた返り値を代入 変数名gradsに空辞書を代入 db2にyに対するa2の偏微分を代入 grads内のb2にdb2のバッチ内合計を代入 grads内のw2にz1の転置行列とdb2の内積を代入 db1にz1に対するa1の偏微分を代入 grads内のb1にdb1のバッチ内合計を代入 grads内のw1にbatchdatの転置行列とdb1の内積を代入 辞書gradsを返り値にして処理を返す 関数名 lossで引数名(x, t)の関数作成:# 損失関数 クラス内predict関数の引数にxを与えたときの返り値をyに代入 クラス内correct関数を引数にy,tを与えて実行 mean_squared_error関数に引数y,tを与えたときの値を返り値にして処理を返す 関数名 loadの関数作成: 'loading...'と出力する './train_img/mnist.pkl'のファイルを開く: datasetに開いたファイル内の変数を代入 処理を返す 関数名 correctで引数名(y, t)の関数作成:# 正答率(データセットを一周するときの最後のバッチで計算) ypreにyで予測された確率の最も高い数字を代入 ansにtで与えられた正解の数字を代入 correct_rateにypreとansが全体の何パーセント一致しているかを代入 処理を返す ``` ### 実行(学習部) ``` clsにクラスClassificationのインスタンスを作成 startにトレーニング開始前の時刻を代入 clsのtrain関数を実行 トレーニングにかかった時間を出力 ``` ### 検出部 ``` startに検出部の開始時刻を代入 testimgに'./search_image.png'のグレースケールの値を代入 halfimに14を代入 coorにx,y座標を追加するために1*2の空行列を作成 testimgarrayに検出して抜き出した画像データを追加するために1*784の空行列を作成 labelにラン解析の結果のラベルを代入するためのtestimgと同様の形のゼロ行列を作成 testimgの行数の範囲でyに代入してループ: testimgの列数の範囲でxに代入してループ: testimg[x,y]が0より大きい時だけlabelに値を代入するために条件分岐: y==0 and x==0で条件分岐: label[y,x]に1を代入 y==0で条件分岐: label[y,x-1]>0で条件分岐: label[y,x]にlabel[y,x-1]を代入: label[y,x-1]>0以外: label[y,x]にlabel内での最大値+1を代入 x==0で条件分岐: label[y-1,x:x+2]のどれかが0より大きい時で条件分岐: raにlabel[y-1,x:x+2]で0より大きい値を抽出して代入 raに2つ値があるときで条件分岐: raを昇順でソート label内のraの大きい値に小さい値を代入 label[y,x]にra[0]の値を代入 上記以外: label[y,x]にlabel内での最大値+1を代入 xがtestimgの最後の値の時で条件分岐: label[y-1,x:x+2]とlabel[y,x-1]のどれかが0より大きい時で条件分岐: raにlabel[y-1,x:x+2]とlabel[y,x-1]で0より大きい値を抽出して代入 raに2つ以上値があるときで条件分岐: raを昇順でソート rにraのサイズ-1の範囲を代入してループ: rの値を+1 label内のra[r]の値にra[0]の値を代入 label[y,x]にra[0]の値を代入 上記以外: label[y,x]にlabel内での最大値+1を代入 上記以外: label[y-1,x-1:x+2]とlabel[y,x-1]のどれかが0より大きい時で条件分岐: raにlabel[y-1,x-1:x+2]とlabel[y,x-1]で0より大きい値を抽出して代入 raに2つ以上値があるときで条件分岐: raを昇順でソート rにraのサイズ-1の範囲を代入してループ: rの値を+1 label内のra[r]の値にra[0]の値を代入 label[y,x]にra[0]の値を代入 上記以外: label[y,x]にlabel内での最大値+1を代入 labelnumにlabelの種類-1を代入 labelnumの範囲でiに代入してループ: iの値を+1 label内にiの値がない時で条件分岐: label内の最大値の値の場所にiの値を代入 labelnumの範囲でiに代入してループ: iの値を+1 posallにlabel内のiのインデックスを代入 xposにposallに代入されたlabelのインデックスの列の最大値と最小値の平均を代入 yposにposallに代入されたlabelのインデックスの行の最大値と最小値の平均を代入 coorに1列目xpos、2列目yposの値を追加 testimgarrayにxpos,yposを中心とした28*28の画像データをreshapeし1行にした行列を追加 ``` ### 分類部 ``` numpreにclsインスタンスのpredict関数に引数(testimgarray)を与えたときの返り値を代入 numpreにnumpreの行方向に最大の値をとるインデックスを返すことで予測された確率の最も高い数字を代入 dfに{'number' : numpre,'xid' : coor[:,0],'yid' : coor[:,1]}としてデータベースを作成 dfの'number'で昇順にソートしたデータベースを出力 検出にかかった時間を出力 ``` ## 工夫点 ニューラルネットワークによる確率計算のため、ラン解析を用いて検出する数字の画像中心のポジションを先に決め、その後、分類した。 ## 実験結果と考察 検出では数pixelのずれはあったが100%取り出せた。 適合率は約70%であった。 学習時間は13.75秒で検出、分類時間は1.725秒であった。 --- ## グループ員の分担事項 |課題|名前| |---|---| |識別器(knn)|本田| |識別器(パーセプトロン多クラス)|山本、中川| |識別器(ロジスティック回帰多クラス)|中川| |mnist|山本| |発表|本田| ## グループ各員の感想(必須) ### 中川 主にロジスティック回帰を担当したが、損失関数の微分が計算しやすいと扱いやすくなることが実感できた。 ### 本田 前回役に立てなかったので、今回は自分なりに色々調べたりして頑張ってみた。自分の考えている機能に合う表現を探し当てた時の感動は落としたコンタクトを見つけた時に匹敵するものがあって興奮した。信号解析のためだけでないpythonの表現を勉強できたので、非常にいい経験となった。 ### 山本 ニューラルネットワークの実装は初めてだったのであまり凝ったものはできなかったが、ラン解析を取り入れるなどの工夫はできたように感じる。また、拡張性が低いプログラムになってしまったと自覚しているので今後の課題として取り組んでいきたい。