Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

dotnetでOpenCvSharpを導入してみる

半年ぐらい前、dotnetGtk#にてGUIの作成を行う記事を公開しました。
elsammit-beginnerblg.hatenablog.com

そこで下記のようなコメントを残していたのですが、、、
やれておりませんでした。。。

                                                                                                                                                                        • -

 ここまでは出来たのですが、OpenCVとの連携が出来ていないです泣
 どうやるのかな??
 最終的にはOpenCVと連携したいので、もう少し調べてみます。
 また分かったらブログにて備忘録残しておこうと思います!!

                                                                                                                                                                        • -

今回、dotnetでOpenCvSharpをインストールする方法とGtk#との連携方法をまとめたいと思います。



■環境

前回はUbuntu16.04を用いましたが、
今回はUbuntu20.04を利用しました。

またGtk#やdotnetのインストールは実施済みの環境を前提とします。

dotnetGtk#を用意

OpenCvSharpをダウンロードする前にdotnetGtk#を用意するまでをまとめておこうと思います。

まずはGtk#を用意するためのディレクトリを作成し、
さらに作成したディレクトリに移動します。

mkdir gtkApp
cd gtkApp

次にこちらのコマンドでGtk#を作成します。

dotnet new gtkapp

コマンド実行が成功していれば、

MainWindow.cs  
MainWindow.glade  
Program.cs

といったファイルが生成されているかと思います。

念のため試しに動かしてみます。
こちらのコマンドで実行可能です。

dotnet run

上手く動作すればこちらのような画面が表示されるかと思います。
f:id:Elsammit:20210418211814p:plain

dotnetでOpenCvSharpインストール

ではOpenCvSharpをインストールしていきます。
先ほど作成したgtkappディレクトリ配下にてこちらのコマンドを実行します。

dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.runtime.ubuntu.18.04-x64

これでOpenCvSharpをdotnetでインストールさせることができます。
すでに環境一式が用意されていたので簡単にインストール出来て便利!!

こちらのOpenCvSharpのインストールですが、
dotnetで新規(GUI)アプリをnewした後に毎度packageをaddする必要があるので注意。

■OpenCvShrpを使ってみる

では実際にOpenCvSharpを組み入れて動かしてみたいと思います。
今回は簡単のために読み出した画像を別画像として保存させてみます。

MainWindow.csのコードはこちらになっているかと思います。

using System;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;

namespace GtkApp
{
    class MainWindow : Window
    {
        [UI] private Label _label1 = null;
        [UI] private Button _button1 = null;

        private int _counter;

        public MainWindow() : this(new Builder("MainWindow.glade")) { }

        private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow"))
        {
            builder.Autoconnect(this);

            DeleteEvent += Window_DeleteEvent;
            _button1.Clicked += Button1_Clicked;
        }

        private void Window_DeleteEvent(object sender, DeleteEventArgs a)
        {
            Application.Quit();
        }

        private void Button1_Clicked(object sender, EventArgs a)
        {
            _counter++;
            _label1.Text = "Hello World! This button has been clicked " + _counter + " time(s).";
        }
    }
}

こちらのコードに対してまずOpenCvSharpを定義します。

using OpenCvSharp;

次にMainWindowコンストラクタ内にこちらのコードを入力します。

Mat mat = new Mat("画像パス");
Cv2.ImWrite("作成画像ファイル名",mat);

最後にクラス名をこちらのように置き換え。

class MainWindow : Gtk.Window

どうやらWindowだけだと、
Gtk.Windowなのか、OpenCvSharp.Windowなのか区別が出来ずエラーになってしまうようです。
先ほどの変更内容を追記したコードがこちら。

using System;
using Gtk;
using OpenCvSharp;
using UI = Gtk.Builder.ObjectAttribute;

namespace GtkApp
{
    class MainWindow : Window
    {
        [UI] private Label _label1 = null;
        [UI] private Button _button1 = null;

        private int _counter;

        public MainWindow() : this(new Builder("MainWindow.glade")) { }

        private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow"))
        {
            Mat mat = new Mat("画像パス");
            Cv2.ImWrite("作成画像ファイル名",mat);

            builder.Autoconnect(this);

            DeleteEvent += Window_DeleteEvent;
            _button1.Clicked += Button1_Clicked;
        }

        private void Window_DeleteEvent(object sender, DeleteEventArgs a)
        {
            Application.Quit();
        }

        private void Button1_Clicked(object sender, EventArgs a)
        {
            _counter++;
            _label1.Text = "Hello World! This button has been clicked " + _counter + " time(s).";
        }
    }
}

こちらを実行してみます。

dotnet run

ディレクトリ内にCv2.ImWriteで指定したファイルが生成されていればOKです。

■(補足)OpenCvSharpビルド手順

補足としてOpenCvSharpビルド手順をまとめておきます。
まずはGitHubより環境一式をダウンロードします。

git clone https://github.com/GtkSharp/GtkSharp.git

次に

cd opencvsharp/src

でsrc配下に移動し、

mkdir build

でビルドディレクトリを作成。
そして、

cmake ..
make
sudo make install
sudo ldconfig

でビルド+インストールを実施し、最後にパスを通しておきます。
成功すれば、OpenCvSharpExternディレクトリが生成され、
配下にlibOpenCvSharpExtern.soファイルが生成されているかと思います。
こちらがLinuxでOpenCvSharpを用いる際の.soファイルになります。

■最後に

今回はdotnetでOpenCvSharp導入手順についてまとめてみました。
次回はGtk#とOpenCvSharpをてGUI画面上に動画や画像の表示をさせてみたいな。と思っております。

別途monodevelopでもOpenCvSharpを導入しようとしているのだけれどこちらはうまく行かず。。。
monodevelopだとNugetも関わってくるからよく分からなくなってくる。
一応自分でビルドした環境を所定の位置に入れてパス通してみたけど動かず。。。困った。



pandasで2次元配列データを加工する

Kaggleを行う上で用意されているデータの加工は重要なファクターになります。
ですが、Kaggleで用意されているデータは穴が抜けていたり、文字列データであったりと扱いにくい場合が多々あります。

今回はこのような扱いにくいデータを加工する手段についてまとめておこうと思います。



■条件

今回はすでに応募が終了している、
bnp-paribas-cardif-claims-management
コンテストで展開されているデータを利用していきます。

■穴抜けデータの存在確認

まず2次元データに対して穴抜けデータが格納されていないか確認していきます。
コードはこちら。

def kesson_table(df): 
    null_val = df.isnull().sum()
    percent = 100 * df.isnull().sum()/len(df)
    cnt = []
    val = []
    pst = []
    for count in range(df.shape[1]):
        if null_val[count] != 0:
            cnt.append(count)
            val.append(null_val[count])
            pst.append(percent[count])
    cnt = pd.DataFrame(cnt)        
    val = pd.DataFrame(val)
    pst = pd.DataFrame(pst)
    kesson_table = pd.concat([cnt, val, pst], axis=1)
    kesson_table_ren_columns = kesson_table.rename(
    columns = {0 : 'Number', 1 : '欠損数', 2 : '%'})
    return kesson_table_ren_columns
kesson_table(train)

kesson_tableが穴抜けデータが存在しないか確認する処理になります。

null_val = df.isnull().sum()

にて各行に対して穴抜けのデータ数をカウントしています。
もし1つでも穴抜けのデータが存在する場合、null_val には0以上の値が格納されます。

このため、

    for count in range(df.shape[1]):
        if null_val[count] != 0:
            cnt.append(count)
            val.append(null_val[count])
            pst.append(percent[count])

にてnull_valが0ではない。すなわち穴あきデータが存在した場合には確認用の配列に格納していきます。
そして最後に2次元配列でデータを格納し、
値を返します。

    cnt = pd.DataFrame(cnt)        
    val = pd.DataFrame(val)
    pst = pd.DataFrame(pst)
    kesson_table = pd.concat([cnt, val, pst], axis=1)
    kesson_table_ren_columns = kesson_table.rename(
    columns = {0 : 'Number', 1 : '欠損数', 2 : '%'})
    return kesson_table_ren_columns

■穴抜けデータの保管

まずはこちらのように、ある数値で埋められた列に対して一部セルが空欄であった場合です。
f:id:Elsammit:20210414230357p:plain

今回はデータの中央値を穴抜けの箇所に代入していきます。
コードはこちら。

train["v1"] = train["v1"].fillna(train["v1"].median())
train["v2"] = train["v2"].fillna(train["v2"].median())
kesson_table(train)

fillna()にて穴抜けになっている箇所に対して括弧内の値で補完します。
補完する値は先ほど記載した通り、

train["v1"].median()
train["v2"].median()

により中央値で補完します。

最後に、

kesson_table(train)

にて補完が完了していることを確認します。

次に文字列データについてです。
こちらのように文字列が格納された列に対して穴あきのケースです。
f:id:Elsammit:20210414231326p:plain

こちらはデータが少なかったり、大多数が同一のデータであれば補完も同じデータにすればよいのですが、
大抵は、
 ・データ量が多い
 ・データ種類複数で大多数のデータが見当たらない
ケースがほとんどです。

そこでまずは各要素とその要素ごとをカウントするところから必要になります。
データ種類とカウント数を算出するコードはこちらになります。

import collections

c = collections.Counter(train["v56"])
print(c)

v56が列番号にあたります。
今回は2次元配列を用いているため特定の列に対する1次元配列にしてチェックを行っております。
ここで、要素の抽出と要素毎のカウントを行うにあたり、
collections.Counter
を用いています。
collections.Counterですが、例えばこちらのような配列に対して実行をすると、

list = ['a', 'a', 'a', 'b', 'b', 'c']

c = collections.Counter(list)
print(c)

こちらのように各要素数に対するカウント数が算出できます。

# Counter({'a': 4, 'c': 2, 'b': 1})

こちらにより再頻出の文字列が抽出できるため、その文字列で穴あきの部分を補完していきます。
例えばv56列で再頻出な文字列が"BW"であった場合、こちらのようなコードで補完が行えます。

train["v56"] = train["v56"].fillna("BW")

こちらは先ほどの数値補完と同じですね。

■文字列の要素を数値に置き換える。

では次に文字列を数値に置き換えてみます。
先ほどのv56列に対して実施してみます。
コードはこちら。

c = collections.Counter(train["v56"])
count = 0
for k in c:
    train.loc[train["v56"] == k, "v56"] = count
    count+=1

先ほどのcollections.Counterで各要素をリスト化させることが出来ます。
このリスト化したデータをfor文により一要素毎に数値に置き換えています。
置き換えにあたり、.locを用いています。
.locですが、

DataFrame型変数.loc['行ラベル名', '列ラベル名']

というように指定することで、指定した行、列についての要素が返ってきます。
今回はこの.locにより行列を指定してその要素に対して数値置き換えを行っています。

■最後に

今回は穴あきのデータ群に対する補完や扱いにくい文字列データを数値データに置き換える方法をまとめました。
機械学習を勉強していると、ただデータがあるだけではだめで正しく整理できていないと扱いにくいのだということを学ぶことが出来て良いですね。
データを収集するところからしっかり考えられるエンジニアになっていきたいな!!



ポケモンステータスからタイプを識別してみる Keras編

先日までkerasで2値や多値分類を行ってきました。
elsammit-beginnerblg.hatenablog.com
elsammit-beginnerblg.hatenablog.com

今回はkerasでポケモンのステータスからタイプを分類してみたいと思います。
このタイプ分類ですが、すでにロジスティック回帰などで実施していますが、
kerasだとどれだけ性能が上がるのか確認したく実施してみました!!
elsammit-beginnerblg.hatenablog.com



■利用データ

利用したポケモンのデータですが、こちらに格納されたデータを用いております。
https://drive.google.com/file/d/0Bx6uOB0FHuuSMXdOclZXTHhhSUE/view

■分類内容

今回は、
・ノーマルタイプ
・はがねタイプ
のどちらのタイプなのか分類してみたいと思います。

■データ加工

すでに前回のブログでまとめておりましたが、念のためこちらで再度まとめておきたいと思います。

先ほどのデータはこちらのようにステータスと名前が列として用意されておりました。
f:id:Elsammit:20210408230232p:plain

こちらのリストからノーマルタイプとはがねタイプを抽出。

poketype2 = "ノーマル"
poketype3 = "はがね"

with codecs.open("/kaggle/input/pokemon-status/pokemon_status.csv", "r", "utf-8", "ignore") as file:
    df = pd.read_table(file, delimiter=",")  

nomal1 = df[df['タイプ1'] == poketype2]
nomal2 = df[df['タイプ2'] == poketype2]
normal = pd.concat([normal1,normal2])

aian1 = df[df['タイプ1'] == poketype3]
aian2 = df[df['タイプ2'] == poketype3]
aian = pd.concat([aian1,aian2])

次にノーマルタイプかはがねタイプかの判定を行うためのフラグをデータの末尾に追加します。

def type_to_num(p_type,typ):
    if p_type == typ:
        return 0
    else:
        return 1

pokemon_m_n = pd.concat([normal, aian], ignore_index=True)
type1 = pokemon_m_n["タイプ1"].apply(type_to_num, typ=poketype3)
type2 = pokemon_m_n["タイプ2"].apply(type_to_num, typ=poketype3)
pokemon_m_n["type_num"] = type1*type2
pokemon_m_n.head()

上記コードを組み合わせて実行してみるとこちらのように選択したいタイプが抽出できかつ末尾に判定用のフラグがセットされております。
f:id:Elsammit:20210408231245p:plain

最後にテストデータとトレーニングデータに分類すればデータ加工・準備は完了です。
全体のコードはこちらになります。

import pandas as pd
from pandas import plotting  
import codecs
import numpy as np

def type_to_num(p_type,typ):
    if p_type == typ:
        return 0
    else:
        return 1
    
poketype2 = "ノーマル"
poketype3 = "はがね"

df = pd.read_csv("pokemon_status.csv")

nomal1 = df[df['タイプ1'] == poketype2]
nomal2 = df[df['タイプ2'] == poketype2]
normal = pd.concat([normal1,normal2])

aian1 = df[df['タイプ1'] == poketype3]
aian2 = df[df['タイプ2'] == poketype3]
aian = pd.concat([aian1,aian2])
    
pokemon_m_n = pd.concat([normal, aian], ignore_index=True)
type1 = pokemon_m_n["タイプ1"].apply(type_to_num, typ=poketype3)
type2 = pokemon_m_n["タイプ2"].apply(type_to_num, typ=poketype3)
pokemon_m_n["type_num"] = type1*type2

X = pokemon_m_n.iloc[:, 7:13].values
y = pokemon_m_n["type_num"].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)
pokemon_m_n.head()

■kerasによるポケモンタイプ分類

ではkerasで分類してみます。
今回はノーマルタイプとはがねタイプを分類してみるため、2値分類になります。
そこで、kerasのモデルをこちらのように作成。

#モデルの定義
model = models.Sequential()
model.add(layers.Dense(64, activation="relu", input_shape=(6, )))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(64, activation="relu"))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(1, activation="sigmoid"))

#モデルの構築
model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy'])

モデルですが、
説明変数は6項目ありますので入力層への入力を6次元に設定。
さらに中間層(隠れ層)を64層用意し、
最後にシグモイド関数により2値分類する
といった構成にしました。

さらにモデルを構築するにあたり、
最適化関数としてrmspropを利用しました。

ではこちらのモデルを用いてポケモンのタイプ分類してみたいと思います。
全体のコードはこちら。

import tensorflow as tf
from sklearn import datasets
from keras.models import Sequential
from keras.layers import Dense, Activation
from matplotlib import pyplot

#モデルの定義
model = models.Sequential()
model.add(layers.Dense(64, activation="relu", input_shape=(6, )))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(64, activation="relu"))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(1, activation="sigmoid"))

#モデルの構築
model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy'])

#学習の実行
history = model.fit(X_train,y_train,epochs=100)

#エポック毎のaccuracy結果グラフ化
pyplot.plot(history.history['accuracy'])
pyplot.title('model accuracy')
pyplot.ylabel('accuracy')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'test'], loc='upper left')
pyplot.show()
    
#評価の実行
score = model.evaluate(X_test,y_test,batch_size=1)
print(score[0])
print(score[1])

エポック数ですが100を設定しました。
レーニングした結果はこちら。
f:id:Elsammit:20210408232557p:plain

テスト結果ですが、

Loss:0.279
Accuracy:0.908

となりました。
結構高い結果が得られました!!
しかしながら、以前実施したロジスティック回帰の場合には0.943であったので少し悪い結果になってしまいました。。。

■別のタイプで確認してみる
ノーマル、はがねタイプの分類では負けてしまいましたが、、、
ほのお、みずタイプでロジスティック回帰とKerasで比較をおこなってみました。
結果ですが、
【ロジスティック回帰】

testデータに対するscore: 0.738

【Keras】

testデータに対するscore:0.803

といった結果になりタイプによっては性能が高いことが分かりました。

■最後に

タイプによってはKerasの方が性能がよさそうですね。
どんな法則があるのでしょう??
ちょっと後で調べてみたいな!!と思います。



Kerasでkaggleの問題を解いてみた

先日、Kerasについてまとめてみました。
elsammit-beginnerblg.hatenablog.com

今回はKerasを用いてkaggleで掲載されている問題を解いてみたいと思います!!
解いていく問題ですが、
 ・Titanic - Machine Learning from Disaster
 ・Otto Group Product Classification
の2種類です。



■Titanic - Machine Learning from Disasterを解いてみる

まずはTitanic - Machine Learning from Disasterです。
学習のためのデータ準備ですが、以前記載したこちらの方法を流用しています。
elsammit-beginnerblg.hatenablog.com


コードはこちら。

from keras import models
from keras import layers
import tensorflow as tf
from sklearn import datasets
from keras.models import Sequential
from keras.layers import Dense, Activation
from matplotlib import pyplot

#訓練データとテストデータの分割
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(features_two, target, test_size=0.2)

#モデルの定義
model = models.Sequential()
model.add(layers.Dense(64, activation="relu", input_shape=(7, )))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(64, activation="relu"))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(1, activation="sigmoid"))

#モデルの構築
model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy'])

#学習の実行
history = model.fit(X_train.astype(np.float32),y_train,epochs=200)

#エポック毎のaccuracy結果グラフ化
pyplot.plot(history.history['accuracy'])
pyplot.title('model accuracy')
pyplot.ylabel('accuracy')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'test'], loc='upper left')
pyplot.show()

#評価の実行
score = model.evaluate(X_test.astype(np.float32),y_test,batch_size=1)
print(score[0])
print(score[1])

基本的には前回記載したように入力層-隠れ層(中間層)-出力層の順番にモデルを作成し、
学習を行っていく流れになります。

ただし今回は、dropoutを導入しより精度の高い評価を目指してみました。

dropoutとは、、、
隠れ層(中間層)のノードを一定の割合で不活性化することを言います。
不活性化は、教師データを用いて学習する際、中間層の一部ノードを以降の学習に使用しないことを言います。
dropoutを用いることで、機械学習の推定精度の向上が見込めるといわれております。

理由はこちらに詳しくまとめられておりますが、
dropoutさせるノードはランダムに決められるため、それぞれ少しづつ異なる教師データを使用して学習します。
これにより疑似的にはなりますが、ディープラーニングを作り出せるため、精度が高くなるということです。
https://aizine.ai/keras-dropout0706/#toc1

エポック数は200とし、実際に先ほどのコードを実行してみました。
結果、各エポック毎のaccuracyをグラフに表すとこちらの通りになりました。
f:id:Elsammit:20210406221729p:plain

200エポックでaccuracyが0.8250になりました。
こちらの学習結果からテストデータで評価を実行した結果、

loss:0.4950
accuracy:0.8156

となりました。
こちらの学習結果を用いて、Submitしてみた結果、、、
スコアは0.775!!
前回も解いたのですがその時の成績は、自分で頑張って0.53、他者のコードを流用して0.73でした。
この時と比較すると改善しております!!
Good!!

■Otto Group Product Classification

こちらもデータの準備は以前記載した方法で準備しました。
elsammit-beginnerblg.hatenablog.com

Kerasを用いたコードはこちら。

import keras
from keras import models
from keras import layers
import tensorflow as tf
from sklearn import datasets
from keras.models import Sequential
from keras.layers import Dense, Activation
from matplotlib import pyplot
 
#モデルの定義
model = Sequential()
model.add(Dense(186,input_dim=93))
model.add(Activation('relu'))
model.add(layers.Dropout(0.5))
model.add(Dense(units=186))
model.add(Activation('relu'))
model.add(layers.Dropout(0.5))
model.add(Dense(units=186))
model.add(Activation('relu'))
model.add(layers.Dropout(0.5))
model.add(Dense(units=9))
model.add(Activation('softmax'))

#モデルの構築
model.compile(loss='sparse_categorical_crossentropy',optimizer='sgd',metrics=['accuracy'])
 
#学習の実行
history = model.fit(X_train, y_train,epochs=100)
 
pyplot.plot(history.history['accuracy'])
pyplot.title('model accuracy')
pyplot.ylabel('accuracy')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'test'], loc='upper left')
pyplot.show()
    
#評価の実行
score = model.evaluate(X_test,y_test,batch_size=1)
print(score[0])
print(score[1])

こちらも先ほどのTitanicと同様に、dropoutを用いて精度を上げております。
また、隠れ層を3層ほど組み合わせてモデルを作成してみました。

ではエポック数100で実行してみます。
結果はこちら
f:id:Elsammit:20210406221650p:plain
accuracyが0.7947で0.8にかなり近づいています。

ではテストデータを用いて評価を行ってみます。
結果は、

loss:0.5220
accuracy:0.7957

でした。
以前記載した方法ですと、
RandomForestですとlossは0.604、
xgboostでlossが0.481
でした。
RandomForestよりは精度高いですが、xgboostより精度が低い結果になりました。

エポック数やdropout率を変えればもう少し精度上がるかもしれないですが、、、
試しに動かしただけにしてはまぁまぁな結果。

■最後に

Kerasで動かしてみましたが結構良い結果が得られて満足。
しかしながら、時間が掛かりますね。
Otto Group Product Classificationですと、先ほどのコードを実行するだけで数分かかってしまいます。
よりデータが複雑になるともっと時間がかかってしまいます。。。
その点では他の学習方法の方がよさそうですね。



Keras基礎をまとめてみた

kaggle挑戦中のElsammitですw
機械学習超初心者ですw

今回はKerasって何?から基礎的な部分をアヤメの分類を例にまとめてみました!!
f:id:Elsammit:20210401224604p:plain



■Kerasとは?

Kerasとは、TensorFlow上で動くニューラルネットワークの1つです。
Kerasを使用するとディープラーニングのベースとなる数学的な部分を気にせずとも比較的短いソースコードで実装することが出来るようになります。

Kerasの他にも同様にニューラルネットワークライブラリとして他にもライブラリが存在しますが、、、
Kerasのメリットとして、
 ・構築が容易
 ・可読性が高い
があります。
しかしながら、計算速度が低く低パフォーマンスであることがデメリットになります。

■Kerasを試してみる

ではKerasを使ってみたいと思います。
まずはアヤメの分類をKerasで行ってみたいと思います!!

import keras
import tensorflow as tf
from sklearn import datasets
from keras.models import Sequential
from keras.layers import Dense, Activation
from matplotlib import pyplot
iris = datasets.load_iris()
 
#モデルの定義
model = Sequential()
model.add(Dense(32,input_dim=4))
model.add(Activation('relu'))
model.add(Dense(units=6,input_dim=32))
model.add(Activation('softmax'))
 
#モデルの構築
model.compile(loss='sparse_categorical_crossentropy',optimizer='sgd',metrics=['accuracy'])
 
#訓練データとテストデータの分割
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(iris.data, iris.target, test_size=0.2)
 
#学習の実行
history = model.fit(X_train,y_train,epochs=100)

#エポック毎のaccuracy結果グラフ化
pyplot.plot(history.history['accuracy'])
pyplot.title('model accuracy')
pyplot.ylabel('accuracy')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'test'], loc='upper left')
pyplot.show()
    
#評価の実行
score = model.evaluate(X_test,y_test,batch_size=1)
print(score[1])

Kerasではモデル定義とモデル構築、学習実行の3段階で構築されます。

モデル構築のコードはこちらになります。

model = Sequential()
model.add(Dense(32,input_dim=4))
model.add(Activation('relu'))
model.add(Dense(units=6,input_dim=32))
model.add(Activation('softmax'))

まずはどんなニューラルネットワークなのかを定義します。
今回はSequentialモデルを用いました。
Sequentialモデルはニューラルネットワークの各層を順番につなげたモデルを表します。

model = Sequential()

次に入力層側隠れ層を作成します。
アヤメは入力の次元が4次元ですので、

model.add(Dense(32,input_dim=4))

としました。
こちらの"32"ですが、隠れ層として32層作成することを意味しております。
そして、活性化関数としてrelu関数を挿入し、

model.add(Activation('relu'))

出力層側の隠れ層を作成します。

model.add(Dense(units=6,input_dim=32))

ここでunitsですが、
出力層の出力数にあたります。

これでモデルの定義が行えました。

次に先ほど定義したモデルを構築していきます。
構築のコードはこちら。

model.compile(loss='sparse_categorical_crossentropy',optimizer='sgd',metrics=['accuracy'])

lossには損失関数を設定し、metricsには評価関数を指定します。
metricsには一般的に['accuracy']を設定するとのこと。

metricsは自分で作った評価関数を渡すことも可能とのこと。

最後に、
optimizerには最適化のためのアルゴリズムを設定します。
今回はSGDを用いました。

そしてそして、、、
学習を実行!!

history = model.fit(X_train,y_train,epochs=100)

エポック数は100に設定。

■kerasでアヤメを分類

では先ほどのコードでアヤメを分類していきます。
まずはエポック毎のトレーニング結果をグラフにまとめました。
f:id:Elsammit:20210401222233p:plain
結構高精度ですね!!

次に評価結果ですが、accuracyは
0.9667
とかなり高精度での分類が行えました!!

■(補足)SGDとは??

SGDとは、確率勾配降下法(stochastic gradient descent)の略で
Optimizerの中でも初期に提唱された最も基本的なアルゴリズムになります。

qiitaにSGDについてまとめられておりましたので、詳細はこちらをどうぞ!!
こちらの記事にはSGDの他にも最適化アルゴリズムがまとめられておりましたので勉強になるかと思います。
https://qiita.com/tokkuman/items/1944c00415d129ca0ee9

■最後に

今回はKerasの基本的なことをまとめてみました!!
Kerasを用いてKaggle内のコンペを解いてみたいと思います。
上手くできたらブログにまとめたいと思います。



Kaggleで過去案件を実施してみる(Otto Group Product Classification実施してみた)

kagglerの仲間入りを果たしたく先日kaggler jaに参加してみました!!
https://kaggler-ja-wiki.herokuapp.com/
f:id:Elsammit:20210324232123p:plain

そこでタイタニック案件を実施した後は過去の案件をいくつか実施した方がよいとのこと。
そして、その中でおすすめされていたのが
Otto Group Product Classification
という案件です。
データが少なめでわかりやすいとのこと。

せっかくなので実施してみることにしました!!



■Otto Group Product Classificationのご紹介

Otto Group Product Classificationでは、
与えられる数値機能からどの商品に分類されるのかを判定・分類することを目的としたコンペとなります。
数値の数は93種類あり、この93種類のデータ値を元にClass1~Class9に分類していくことになります。

■データ

次に与えられたデータです。
trainデータ、testデータに対して

train.head()
test.head()

を実行してデータの形態を確認します。
結果trainデータは、
f:id:Elsammit:20210323224113p:plain
といった形になっており、
testデータは、
f:id:Elsammit:20210323224421p:plain
といった形になっております。

■データ加工

今回のコンペでは93種類のデータからどの商品に分類するのかを判定するのですが、
trainデータを確認すると目的変数がClass_1からClass_9と文字列になっております。
そこで、こちらのClass_1からClass_9を文字列から数値に変換していきます。
コードはこちら。

train["target"][train["target"] == "Class_1" ] = 0
train["target"][train["target"] == "Class_2" ] = 1
train["target"][train["target"] == "Class_3"] = 2
train["target"][train["target"] == "Class_4" ] = 3
train["target"][train["target"] == "Class_5" ] = 4
train["target"][train["target"] == "Class_6"] = 5
train["target"][train["target"] == "Class_7" ] = 6
train["target"][train["target"] == "Class_8" ] = 7
train["target"][train["target"] == "Class_9"] = 8

train.head()

こちらを実行することで、
f:id:Elsammit:20210324220403p:plain
と言ったようにtargetがClass_1 ⇒ 0に変わっていることが確認できます。

では学習のためにtrainデータを目的変数と説明変数に分けたいと思います。
コードはこちら。

from sklearn.preprocessing import LabelEncoder, OneHotEncoder

X = train.drop(['id','target'],axis = 1)
y = train['target']
result = LabelEncoder()
y = result.fit_transform(y)

Xに説明変数であるfeat_1 ~ feat_93を格納し、
yに目的変数であるtargetを格納しております。
ここで、目的変数はこのままだと学習を行う際にラベルがないとのエラーが発生してしまいます。
そこで、

result = LabelEncoder()
y = result.fit_transform(y)

と変換を行っております。

LabelEncoderとは、、、
文字列や数値で表されたラベルを,0~(ラベル種類数-1)までの数値に変換してくれるもの
です。
https://gotutiyan.hatenablog.com/entry/2020/09/08/122621

これで機械学習を行う上でのデータ加工は完了です。

機械学習行ってみる

では得られたデータを元に機械学習を行っていきたいと思います!!

まずはロジスティック回帰で分類してみたいと思います。

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import log_loss

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1)

lr = LogisticRegression(C=1.0)
lr.fit(X_train, y_train)

y_pred = lr.predict_proba(X_test)

print(log_loss(y_test,y_pred))

今回はどれだけ間違えたのかを判定するためにLog lossでの判定を行いました。
結果は、、、

0.639

ちょっと誤判定多いですね😅

う~~ん。。
微妙ですね😅

ということで、過去の案件では何を使用しているのか確認!!
結果、
・RandomForest
・xgboost
の2種類を用いているようでした。

そこで2種類のアルゴリズムで確認を実施!!
まずはRandomForest。
コードはこちら。

from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier().fit(X_train, y_train)
y_pred = model.predict_proba(X_test)
from sklearn.metrics import log_loss

print(log_loss(y_test,y_pred))

結果は、、

0.604

ロジスティック回帰よりも精度が良くなりましたね。

では次にxgboost。
コードはこちら。

from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb

model = xgb.XGBClassifier().fit(X_train, y_train)
y_pred = model.predict_proba(X_test)
from sklearn.metrics import log_loss

print(log_loss(y_test,y_pred))

結果は、、

0.481

アルゴリズムと比べて大幅に改善しました!!

Score上位ランカーは0.4を切っているようです。
いやはやすごい。。

■最後に

もっと他の方のコードも確認して、
どのようにして判定すればより誤判定を少なくすることが出来るのか勉強していきたいと思います!!

ただ、、、
機械学習は独学は結構厳しいですね😅
以前Qiitaを見ていた時にCoursaで勉強している人がいたので自分もやってみようかな?🤔
後はkaggleで他者のkernelを読み漁っていこうかな?と思います!!
コードを見ると勉強になりますからね!!


scss、sass導入手順

今回はscss、sass導入手順です。



■そもそもscss、sassって?

まずはscss、sassについてまとめておきます。

scss、sassはcssをより簡単に記載することが出来る言語になります。

sassの略語は、
Syntactically Awesome StyleSheet

・Syntactically = 構文的に
Awesome =  驚くべき
・StyleSheet = スタイルシート

であり、驚くべきスタイルシートのことを指しておりますw

scssはcssに似た形で、括弧書きでの記載となり、
sassはRubyに似た形で改行での書き方になります。

例えば、css、scss、sassはこちらのような違いになります。

.test {
  margin: 10px;
}

.test a {
  padding: 10px 20px;
}
.test{
margin:10px;
    a{
     padding:10px 20px;
   }
}
.test
    margin:10px
a
    color:#12cacc;
    padding:10px 20px;

scss、sassどちらも簡易的な形で記載出来ていますね!!
後、sassは括弧書きが消えているので文字数が減っています。
後、scss、sassであれば変数が利用できます!!

個人的にはscssの方が括弧で範囲がくくられているので可読性高いのかな?
と思っておりますが、どうなのかな?🤔
確かにインデントの方が入力量減るしこっちの方がいいのかな?

こちらのscssやsassですが、コンパイルが必要になります。
今回はこのコンパイル環境の構築について、Linuxでの構築方法とWindows(VS Code)での構築方法の2つを記載していこうと思います!!

Windows(VS Code)での構築方法

まずはWindowsというかVisual Studio Code(VS Code)でのコンパイル環境構築手順です。

事前にVS Codeをダウンロードしてください。
ダウンロード手順についてはこちらにまとまっておりますので、ダウンロードしてみてください。
https://techacademy.jp/magazine/39548

Visual Studio Codeを立ち上げ、左タブの拡張機能ボタンを押下。
f:id:Elsammit:20210321215042p:plain

そして、入力タブにて" Live Sass Compiler"を入力してインストールを押下!!
f:id:Elsammit:20210321215406p:plain

これでOKです!!

合わせてLive Serverという拡張機能をインストールしておくとsass、scssを保存したのと同時にコンパイルが実行されて便利です!
Live Serverは先ほどのLive Sass Compilerと同様に入力タブ入力⇒インストールすればOK。

試しに、test.scssファイル作成し、

.test{
margin:10px;
    a{
     padding:10px 20px;
   }
}

を記載して保存してみます。
もしかしたら、下部のCompile Heroがoffになっているかもしれません。
この状態だとせっかく保存に合わせてコンパイル自動実行される状態にしたのにコンパイルが実行されません😅
その場合にはCompile Heroをクリック頂けるとonになるので実施してみてください。

Linuxへのコンパイル導入手順

次にLinuxでのコンパイル導入の手順です。

コンパイラを導入するにあたり、rubygemsが必要になります。
そこでまずはこちらを実行。

sudo apt-get install ruby rubygems

インストールが完了したら、

sudo gem install sass

を実行!!
こちらのコマンドを実行し、エラーなくバージョンが表示されれば環境構築完了です。

sass --version

では試しに簡単なscssを作成してコンパイルによりcssを生成してみたいと思います。
VS Codeの時とどうように、test.scssファイル作成後、

.test{
margin:10px;
    a{
     padding:10px 20px;
   }
}

を記載して保存します。
そして、

sass test.scss test.css

を実行し、test.cssが生成されていればOKです。

■最後に

個人的には変数を用いることが出来るのが便利だな。と思っております。
今後はscss、sassを有効に利用していきたいな!!と思っております👍