keras2とchainerの使い方をCNNでくらべてみる
目的:keras2とchainerの使い方の違いを知る
まとめ:
keras2はmodelの最初の層以外の入力は記述しなくても良い。バックエンドがtheanoとtensorflowで入力の配列が異なる。
chainerはmodelの層追加時、入力と出力の数を記入。入力でNoneと記述すると自動的に計算してくれる。Conv->Linearの際に便利。
参考:
出力ノード数を手計算せずにConvolutionの出力をLinearに入力する(chainer 1.15) - Qiita
わかりやすい↓
Chainer: ビギナー向けチュートリアル Vol.1 - Qiita
わかりやすい↓
Keras tips: 様々な画像の前処理をカンタンにやってくれるkeras.preprocessingのまとめ - MATHGRAM
keras2
mnistをcnnで学習するサンプル
'''Trains a simple convnet on the MNIST dataset. Gets to 99.25% test accuracy after 12 epochs (there is still a lot of margin for parameter tuning). 16 seconds per epoch on a GRID K520 GPU. ''' from __future__ import print_function import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras import backend as K batch_size = 128 num_classes = 10 epochs = 12 # input image dimensions img_rows, img_cols = 28, 28 # the data, shuffled and split between train and test sets (x_train, y_train), (x_test, y_test) = mnist.load_data() # backendがtensorflowとtheanoで配列のshapeが異なる if K.image_data_format() == 'channels_first': x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols) # theano x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1) # tensorflow x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 print('x_train shape:', x_train.shape) print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), # 32:出力を与える activation='relu', input_shape=input_shape)) # input_shape = x_train.shape[1:]としてもよい。最初のみ入力の値(img_rows, img_cols, 1)が必要。 model.add(Conv2D(64, (3, 3), activation='relu')) # 畳み込み。32:出力だけ与える model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(128, activation='relu')) # 全結合相。2:出力だけ与える model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) # 活性化関数 model.compile(loss=keras.losses.categorical_crossentropy, # 損失関数 optimizer=keras.optimizers.Adadelta(), # 最適化 metrics=['accuracy']) model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test)) # 学習 score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1]) model.save('./model.hdf5')
参考: keras/mnist_cnn.py at master · fchollet/keras · GitHub
予測するサンプル * 写真を一枚指定しそのクラスを出力
# coding: UTF-8 from __future__ import print_function import keras from keras.models import load_model from keras.preprocessing import image import numpy as np import sys model = load_model('model.hdf5') if len(sys.argv) != 2: print("usage: python [image file]") sys.exit(1) filename = sys.argv[1] img = image.load_img(filename, target_size=(32, 32)) x = image.img_to_array(img) #x = x / 255.0 #この操作を行うと正しく予測されない(TBD) # rows, cols, channels) -> (samples, rows, cols, channels) x = np.expand_dims(x, axis=0) pred = model.predict(x) print(pred)
参考: KerasでVGG16を使う - 人工知能に関する断創録
chainer
mnistをcnnで学習するサンプル
# -*- coding: utf-8 -* import numpy as np import matplotlib.pylab as plt from sklearn.datasets import fetch_mldata import chainer import chainer.links as L import chainer.functions as F from chainer import Chain, optimizers, Variable, serializers mnist = fetch_mldata('MNIST original', data_home='.') mnist.data = mnist.data.astype(np.float32) # image data 784*70000 [[0-255, 0-255, ...], [0-255, 0-255, ...], ... ] mnist.data /= 255 # to 0-1 mnist.target = mnist.target.astype(np.int32) # label data 70000 N = 60000 x_train, x_test = np.split(mnist.data, [N]) t_train, t_test = np.split(mnist.target, [N]) # to (n_sample, channel, height, width) x_train = x_train.reshape((len(x_train), 1, 28, 28)) x_test = x_test.reshape((len(x_test), 1, 28, 28)) class CNN(Chain): def __init__(self): super(CNN, self).__init__( conv1 = L.Convolution2D(1, 20, 5), # 入力:1 , 出力:20。両方記述。filter 5 conv2 = L.Convolution2D(20, 50, 5), # 入力:1 , 出力:20。両方記述。filter 5 l1 = L.Linear(800, 500), # ここの入力の計算は以下の参考HPを参照。 l2 = L.Linear(500, 500), l3 = L.Linear(500, 10, initialW=np.zeros((10, 500), dtype=np.float32)) ) def forward(self, x): h = F.max_pooling_2d(F.relu(self.conv1(x)), 2) h = F.max_pooling_2d(F.relu(self.conv2(h)), 2) h = F.relu(self.l1(h)) h = F.relu(self.l2(h)) h = self.l3(h) return h model = CNN() optimizer = optimizers.Adam() # 最適化関数 optimizer.setup(model) n_epoch = 5 batch_size = 1000 for epoch in range(n_epoch): sum_loss = 0 sum_accuracy = 0 perm = np.random.permutation(N) for i in range(0, N, batch_size): x = Variable(x_train[perm[i:i+batch_size]]) t = Variable(t_train[perm[i:i+batch_size]]) y = model.forward(x) model.zerograds() loss = F.softmax_cross_entropy(y, t) # 活性化関数と損失関数 acc = F.accuracy(y, t) loss.backward() optimizer.update() sum_loss += loss.data*batch_size sum_accuracy += acc.data*batch_size print("epoch: {}, mean loss: {}, mean accuracy: {}".format(epoch, sum_loss/N, sum_accuracy/N)) cnt = 0 for i in range(10000): x = Variable(np.array([x_test[i]], dtype=np.float32)) t = t_test[i] y = model.forward(x) y = np.argmax(y.data[0]) if t == y: cnt += 1 print("accuracy: {}".format(cnt/10000)) serializers.save_npz("model.npz", model)
予測するサンプル1(TBD)
import numpy as np %matplotlib inline import matplotlib.pylab as plt from sklearn.datasets import fetch_mldata import chainer import chainer.links as L import chainer.functions as F from chainer import Chain, optimizers, Variable, serializers mnist = fetch_mldata('MNIST original', data_home='.') mnist.data = mnist.data.astype(np.float32) # image data 784*70000 [[0-255, 0-255, ...], [0-255, 0-255, ...], ... ] mnist.data /= 255 # to 0-1 mnist.target = mnist.target.astype(np.int32) # label data 70000 N = 60000 x_train, x_test = np.split(mnist.data, [N]) t_train, t_test = np.split(mnist.target, [N]) # to (n_sample, channel, height, width) x_train = x_train.reshape((len(x_train), 1, 28, 28)) x_test = x_test.reshape((len(x_test), 1, 28, 28)) class CNN(Chain): def __init__(self): super(CNN, self).__init__( conv1 = L.Convolution2D(1, 20, 5), # 入力:1 , 出力:20。両方記述。filter 5 conv2 = L.Convolution2D(20, 50, 5), # 入力:1 , 出力:20。両方記述。filter 5 l1 = L.Linear(800, 500), # ここの入力の計算は以下の参考HPを参照。 l2 = L.Linear(500, 500), l3 = L.Linear(500, 10, initialW=np.zeros((10, 500), dtype=np.float32)) ) def forward(self, x): h = F.max_pooling_2d(F.relu(self.conv1(x)), 2) h = F.max_pooling_2d(F.relu(self.conv2(h)), 2) h = F.relu(self.l1(h)) h = F.relu(self.l2(h)) h = self.l3(h) return h model = CNN() serializers.load_npz("model.npz", model) image_data = (TBD) x = Variable(np.array([image_data], dtype=np.float32)) y = model.forward(x) y = np.argmax(y.data[0])
予測するサンプル2 : 機械学習フレームワークchainerを使って1からコードをかいてみる(mnist編) - Qiita
def forwardではなくdef callにすると
class MLP(Chain): def __init__(self): super(MLP, self).__init__( l1=L.Linear(784, 100), l2=L.Linear(100, 100), l3=L.Linear(100, 10), ) def __call__(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) y = self.l3(h2) return y
以下のようにpredictorで予測することができる
def predict(model, x_data): x = Variable(x_data.astype(np.float32)) y = model.predictor(x) return np.argmax(y.data, axis = 1)
答え合わせ。モデルの保存
def predict(model, x_data): x = Variable(x_data.astype(np.float32)) y = model.predictor(x) return np.argmax(y.data, axis = 1)
予測サンプル3 : Chainer: ビギナー向けチュートリアル Vol.1 - Qiita
import numpy as np from chainer import serializers from chainer.cuda import to_gpu from chainer.cuda import to_cpu model = MLP() serializers.load_npz('mnist_result/model_epoch-10', model) model.to_gpu(gpu_id) %matplotlib inline import matplotlib.pyplot as plt x, t = test[0] plt.imshow(x.reshape(28, 28), cmap='gray') plt.show() print('label:', t) x = to_gpu(x[None, ...]) y = model(x) y = to_cpu(y.data) print('predicted_label:', y.argmax(axis=1)[0])
参考:
Chainerでニューラルネットワーク及び畳み込みニューラルネットワークを実装してみた – データ分析エンジニアが気まぐれに更新するブログ
https://github.com/nocotan/chainer-examples/blob/master/examples/mnist-cnn.py
Convolutional Neural Networkを実装する - Qiita
機械学習フレームワークchainerを使って1からコードをかいてみる(mnist編) - Qiita
Chainer: ビギナー向けチュートリアル Vol.1 - Qiita
わかりやすい ↓
C++のお勉強(2)
一歩ずつ!
型・インスタンス・オブジェクト
構造体は型、型を使って作られた変数はインスタンス。特に、構造体は意味のある情報の塊なので、構造体変数のことをオブジェクトということがある。
アクセスの仕方:①オブジェクト.メンバ ②オブジェクトのポインタ->メンバ
列挙型
何らかのフラグを宣言するときによく用いられる
enum ResultFlag{ Success = 1, Failure = 0 }
三項演算子
a > b ? a : b 真ならばa、偽ならばb
静的変数
プログラムが実行される前にすでに位置がきまっている変数のこと。グローバル変数は静的変数。
初期化はローカル変数であっても一度しか行われない。関数を抜けても値が保存される。
スコープ
::をつけるとグローバル関数にアクセスできる
#inculde <iostream> int a = 1; int main(){ std::cout<< ::a << std::endl; }
メモリの動的確保
newとdeleteはセット。newでメモリを動的に確保でき、ポインタで受ける。
int *p = new int; *p = 0; cout << *p << endl; delete p;
配列
int *array; cin >> size; array = new int[size] delete[] array;
ポインタ
アドレスを入れることのできる変数
ポインタと参照の違い
参照は初期化時に一度参照を決めたら変更できないのに対し、ポインタは再代入すれば何度でも書き換えることが可能。その代わりポインタは*をつけないと参照先のメモリにアクセスできない。
const
ポインタや参照の前にconstをつけると参照先の値の変更ができなくなる。
int StrCount(char* str, char ch){ if (str[i] = ch) < contents > } //書き換わってしまう int StrCount(const char* str, char ch){ if (str[i] = ch) < contents > } //書き換わらない
本来はstr[i] == chとしたかったので、constとするとエラーにより気づくことができる
const char* p //参照先の値が定数 char* const p = &a //ポインタpが定数 const char* const p = &a //両方定数
コピーコンストラクタ
参考: コピーコンストラクタ
初期化と代入の違い
b = a ; //代入 コピーコンストラクタが呼ばれない intArray b = a; //初期化->コピーコンストラクタ intArray b(a); //初期化->コピーコンストラクタ
継承
privateは派生クラスにさえ公開されない。派生クラスにのみ公開する場合はprotectedにする。
基底クラスからコンストラクタが呼ばれ、派生クラスからデストラクタが呼ばれる。
基底クラスのコンストラクタに引数を持つ、派生クラスのコンストラクタを呼ぶときは以下のように指定する。
コンストラクタ(仮引数リスト) : 基底クラス名(実引数のリスト) , メンバ変数(初期化の値) { ... }
補足:基本の方であってもコンストラクタを持っている
int x(3); int x = 3;
参考:
アップキャスト
派生クラスのオブジェクトは基底クラスへの参照に渡すことができ、この暗黙のキャストをアップキャストという。
オーバーライド
同じ形の関数を派生クラスで再定義することをオーバーライドという。virtualをつけるとアップキャストしても派生クラスのメンバ関数が呼ばれる。
class hoge{ public: virtual bool Set(); };
オーバーライドとアップキャストなどで得られる性質をポリモーフィズムという
純粋仮想関数
protected: virtual void HogeBase() = 0
のようにvirtual ~ =0とすると純粋仮想関数になる。これが含まれているクラスは抽象クラスとよばれ、オブジェクトが作れない。
テンプレート
テンプレート引数、実引数
templete <typename TYPE> // <- テンプレート引数 void Test(TYPE* num, TYPE value) { int a = 1 } Test(0.1 , 0) //コンパイルエラー ∵double か intかわからない Test<double>(0.1 , 0) // <-テンプレート実引数
テンプレートクラス
templete <typename TYPE> class Array{...} int Array::Size() const{...} // コンパイルエラー ∵Arrayはクラステンプレートでクラスではない int Array<int>::Size() const{...} //テンプレート引数をもって初めてクラスになる int Array<double>::Size() const{...} //テンプレート引数をもって初めてクラスになる //↓ templete <typename TYPE> int Array<TYPE>::Size() const {...} //テンプレート引数をもって初めてクラスになる
エラー処理
try { if (エラー判定処理){ throw エラーメッセージ; } }catch(変数宣言){ エラー処理 }
throwなどで投げれれた例外は伝播するので、関数内で発生してもそれを用いている上位でtry catchがあれば、処理される。
例外のキャッチ漏れが無いように注意しよう。
例外の再送出
try{ throw "エラー発生" catch(...){ //したい処理をする throw; }
例外はアップキャスト可能
できる限り、基底クラスから離れた例外でcatchするようにしよう。
Exceptionへの参照のキャッチはできる限り使わない。ex:OpenFileExceptionなど基底クラスから離れたものを使う。
参考: ロベールのC++教室 - 第15章 アップキャスト -
メンバ初期化子
参考: メンバ初期化子 - ぷろみん
イテレータ
イテレータとは? | C++ フリーでぷろぐらみんぐさんから抜粋。わかりやすい。
#include <cstdlib> #include <iostream> vector<int> vec; vector<int>::iterator i; int sum = 0; vec.push_back(1); vec.push_back(2); vec.push_back(3); for(i=vec.begin(); i!=vec.end(); ++i){ sum += *i; } cout << sum << endl; // 6
参考: C++ iterator 入門
分類のお勉強
sklearnを用いた2クラス分類
#!/usr/bin/env python # coding: utf-8 import numpy as np from sklearn import datasets from sklearn import cross_validation from sklearn import metrics # DataSetの準備 iris = datasets.load_iris() # トレーニングデータ <type 'numpy.ndarray'>の(100,4) data = iris.data[0:100] # ラベルデータ (100) target = [] for t in iris.target[0:100]: if t==1: target.append(1) else: target.append(-1) # 全体のデータの2割を検証用 train_x, test_x, train_y, test_y = cross_validation.train_test_split(data, target, test_size=0.2) # 最小二乗法で学習 w = np.linalg.inv(train_x.T.dot(train_x)).dot(train_x.T).dot(train_y) # 最小二乗法で推定 for x in test_x: if w.dot(x) > 0: pred_y = np.array([1 if w.dot(x) > 0 else -1 for x in test_x]) # テストデータに対する正答率 print metrics.accuracy_score(test_y, pred_y)
参考:
Home · levelfour/machine-learning-2014 Wiki · GitHub
https://kaigi.org/jsai/webprogram/2012/pdf/340.pdf
とにかくCNNに学習させる大量の画像データが欲しいでごわすという人のためのスクリプト - shi3zの長文日記
画像データの2クラス分類
#!/usr/bin/env python #-*- encoding: utf-8 -*- from PIL import Image import numpy as np import os import pandas as pd import pylab as pl from sklearn.decomposition import RandomizedPCA from sklearn.externals import joblib from sklearn.svm import LinearSVC # STANDARD_SIZE = (300, 167) STANDARD_SIZE = (480, 640) def img_to_matrix(filename, verbose=False): img = Image.open(filename) if verbose: print 'changing size from %s to %s' % (str(img.size), str(STANDARD_SIZE)) img = img.resize(STANDARD_SIZE) imgArray = np.asarray(img) return imgArray # imgArray.shape = (167 x 300 x 3) def flatten_image(img): s = img.shape[0] * img.shape[1] * img.shape[2] img_wide = img.reshape(1, s) return img_wide[0] def main(): img_dir = 'images/' images = [img_dir + f for f in os.listdir(img_dir)] labels = ['takuya' if 'takuya' in f.split('/')[-1] else 'iron_man' for f in images] #labels = ['takuya' if 'takuya' in f.split('/')[-1] else 'iron_man' for f in images] #print images #print labels data = [] for image in images: img = img_to_matrix(image) img = flatten_image(img) data.append(img) data = np.array(data) #print data.shape # dataの数だけ一様乱数を生成し、0.7以下のものだけtrainに is_train = np.random.uniform(0, 1, len(data)) <= 0.7 # np.array(labels) == 'takuya'の時は1を、そうでないときは0を返す # yはlabel y = np.where(np.array(labels) == 'takuya', 1, 0) # train用をぶちこむ train_x, train_y = data[is_train], y[is_train] # plot in 2 dimensions # 主成分分析 pca = RandomizedPCA(n_components=2) # 分析結果を元にデータセットを主成分に変換する X = pca.fit_transform(data) #print X.shape df = pd.DataFrame({"x": X[:, 0], "y": X[:, 1], "label": np.where(y == 1, 'takuya', 'iron_man')}) colors = ['red', 'yellow'] for label, color in zip(df['label'].unique(), colors): mask = df['label'] == label pl.scatter(df[mask]['x'], df[mask]['y'], c=color, label=label) pl.legend() pl.savefig('pca_feature.png') # training a classifier pca = RandomizedPCA(n_components=5) train_x = pca.fit_transform(train_x) # C : ペナルティ項 svm = LinearSVC(C=1.0) svm.fit(train_x, train_y) joblib.dump(svm, 'model.pkl') # evaluating the model test_x, test_y = data[is_train == False], y[is_train == False] test_x = pca.transform(test_x) print pd.crosstab(test_y, svm.predict(test_x), rownames=['Actual'], colnames=['Predicted']) if __name__ == '__main__': main()
参考:
pythonを使って簡単な画像分類を実現する - stMind
Numpyのwhereで配列インデックスを取得(python) | コード7区
Python: scikit-learn で主成分分析 (PCA) してみる - CUBE SUGAR CONTAINER
scikit.learn手法徹底比較! SVM編 - Risky Dune
オブジェクト指向プログラミング(OOP)のお勉強
C++をベースの考えてみる
c++のコンパイルの仕方
参考
構造化言語では解決できない2つの問題
- グローバル変数
- 再利用性
参考:いまさら聞けない構造化手法とオブジェクト指向の違い(めっちゃわかりやすい) http://www.ogis-ri.co.jp/casestudy/docs/CaseStudy_ESEC2010_StructOO.pdf
OOPの優れた3つの仕組み
- クラス
- ポリモーフィズム
- 継承
これらは構造化言語の課題を解決することができる。重複した無駄なロジックを排除し、必要な機能を整理整頓する仕組みを提供する。
参考:
新人プログラマに知っておいてもらいたい人類がオブジェクト指向を手に入れるまでの軌跡 - Qiita
クラスとは
関連性の強いサブルーチンとグローバル変数を1つにまとめて粒度の大きいソフトウェアを作る仕組み
- サブルーチンと変数をまとめる
- クラスの内部だけで使うサブルーチンを隠す
- 一つのクラスからインスタンスをたくさん作る
クラスの効能1:まとめる
結びつきの強いサブルーチンとグローバル変数を一つのクラスにまとめることができ、以下のメリットが得られる。
- 部品数が減る
- メソッドの名前付けが楽になる
- メソッドが探しやすくなる
まとめ前
- 準備:test.txtにatomと記入
#include <iostream> #include <fstream> using namespace std; fstream file; int fileNO; void openFile(const char* fileName){ file.open(fileName, ios::in); } void closeFile(){ file.close(); } char readFile(){ char str; file.get(str); return str; } int main(){ char result; const char* filename = "test.txt"; openFile(filename); result = readFile(); closeFile(); cout << result << endl; }
結果:
a
まとめ後
#include <iostream> #include <fstream> using namespace std; class TextFileReader{ //クラスという単位で見ると一つに!また、大きなまとまりになるため探しやすい!! private: fstream file; int fileNO; public: void open(const char* fileName){ //名前がシンプルに!!! file.open(fileName, ios::in); } void close(){ file.close(); } char read(){ char str; file.get(str); return str; } }; int main(){ char ch1; char ch2; const char* filename = "test.txt"; TextFileReader reader1; reader1.open(filename); ch1 = reader1.read(); reader1.close(); cout << ch1 << endl; TextFileReader* reader2 = new TextFileReader; reader2->open(filename); ch2 = reader2->read(); reader2->close(); delete reader2; cout << ch2 << endl; }
結果:
a
a
クラスの効能2:隠す
クラスに定義した変数やメソッドを他のクラスから隠すことができる
これにより保守性悪化の原因となるグローバル変数を使わずにプログラムを書くことができる。
上記コードの抜粋↓
class TextFileReader{ private: //privateとするとクラス内部にあるメソッドだけがアクセスできる!変更されたないし、勝手にいじらせへんよ〜 fstream file; int fileNO; public: //アプリケーションのどこからでもアクセスできる!いつでも呼び出してや〜 void open(const char* fileName){ file.open(fileName, ios::in); } void close(){ file.close(); } char read(){ char str; file.get(str); return str; }
ちなみになにもしてしないと勝手にprivateになるよ〜
クラスの効能3:たくさん作る
インスタンスはクラスを定義しておけばそこから実行時にいくつでも作る(メモリ領域を確保する)ことができる
そのインスタンスのメソッドの呼び方↓
インスタンスを格納する変数. メソッド名(引数)
インスタンスを格納する変数ポインタ->メソッド名(引数)
- 準備:robot1.txtにatomと記入 . robot2.txtにbig hero 6 と記入.
#include <iostream> #include <fstream> using namespace std; class TextFileReader{ private: fstream file; int fileNO; public: void open(const char* fileName){ file.open(fileName, ios::in); } void close(){ file.close(); } char read(){ char str; file.get(str); return str; } }; int main(){ char ch1; char ch2; char ch3; const char* filename1 = "robot1.txt"; const char* filename2 = "robot2.txt"; TextFileReader* reader1 = new TextFileReader; //インスタンス一つ目製造 TextFileReader* reader2 = new TextFileReader; //インスタンス二つ目製造 reader1->open(filename1); ch1 = reader1->read(); reader1->close(); reader2->open(filename2); ch2 = reader2->read(); reader2->close(); delete reader1; delete reader2; // open(filename); // result = read(); // close(); cout << ch1 << endl; cout << ch2 << endl; TextFileReader reader3; //インスタンス三つ目製造 reader3.open(filename1); ch3 = reader3.read(); reader3.close(); cout << ch3 << endl; }
結果:
a
b
a
インスタンス変数、グローバル変数、ローカル変数
インスタンス変数
- 別クラスからアクセスできないよう隠すことができる
- 一度インスタンス化されば破棄されるまでメモリ上に残る
ポリモーフィズム(多様性)とは(インターフェースの継承)
共通メインルーチンを作るための仕組み、つまり、呼び出す側のロジックを一本化する
ポリモーフィズムはサブルーチンを呼び出す側のロジックを一本化する仕組み、共通サブルーチンを作る仕組み
継承(実装の継承)
クラス定義の共通部分を別クラスにまとめて、コードの重複を排除する仕組み
型にはまろう
型を指定することのメリットは 1. コンパイラにメモリ領域を教える 1. プログラムのエラーを防止する
型にクラスを指定できる
型チェックには強い型付けと弱い型付けの2種類の方式がある
python:弱い型付け(実行時点でエラーを検出)
ポリモ・継承・型はめのサンプル
基底クラス | 派生クラス | mainクラス |
---|---|---|
Stream | <- InputStream | Polymorphism |
<- ArrayStream |
Stream.h
#ifndef STREAM_H_ #define STREAM_H_ class Stream { public : double Get() const; virtual bool Set() = 0; //純粋仮想関数->このクラス(抽象クラス)は実体をつくることができない。 //virtual bool Set(); //仮想関数 private : double m_n; }; #endif
Stream.cpp
#include "Stream.h" #include <iostream> using namespace std; double Stream::Get() const { return m_n; } // bool Stream::Set() { // cout << "Stream::Set" << endl; // m_n = -1; // return false; // }
InputStream.h
#ifndef INPUTSTREAM_H_ #define INPUTSTREAM_H_ #include "Stream.h" class InputStream : public Stream{ //継承することでGetを定義する必要がなくなる。(コードの重複を排除) public: bool Set(); }; #endif
InputStream.cpp
#include "InputStream.h" #include <iostream> using namespace std; bool InputStream::Set(){ //Setをオーバーライド cin >> m_n; return m_n >= 0; }
ArrayStream.h
#ifndef ARRAYSTREAM_H_ #define ARRAYSTREAM_H_ #include "Stream.h" class ArrayStream : public Stream //継承することでGetを定義する必要がなくなる。(コードの重複を排除) { public : ArrayStream(const double* array); bool Set(); private: const double* m_array; int m_i; }; #endif
ArrayStream.cpp
#include "ArrayStream.h" ArrayStream::ArrayStream(const double* array){ m_array = array; m_i = 0; } bool ArrayStream::Set(){ //Setをオーバーライド m_n = m_array[m_i]; if ( m_n >= 0){ ++m_i; return true; }else{ return false; } }
Polymorphism.cpp
#include "InputStream.h" #include "ArrayStream.h" #include <iostream> using namespace std; bool Average(Stream& stream){ //こうすることで、InputStreamとArrayStreamr両方のAverage関数を作る必要がなくなる。(呼び出す側のロジックの一本化) int count; double avr = 0; for( count = 0 ; stream.Set(); ++count){ //virtual bool Set() = 0;サブクラスのSetが呼ばれる。virtualがないとスーパークラスのSetが呼ばれる。 avr += stream.Get(); } if (count == 0){ return false; } avr /= count; cout << "平均値は" << avr << "です。" << endl; return true; } int main () { InputStream istream; //型の**クラス**指定 Average(istream); //アップキャスト static const double ARRAY[] = {0.5, 1.5, -1}; ArrayStream astream(ARRAY); //型の**クラス**指定 Average(astream); //アップキャスト }
$ g++ Stream.cpp InputStream.cpp ArrayStream.cpp Polymorphism.cpp
結果 :
1
2
3
-1
平均値は2です。
平均値は1です。
パッケージ
クラスをさらにまとめる仕組み
#include <iostream> using namespace std; namespace { //無名名前空間 void PowerOn(){ cout << "Robot Start" << endl; } } namespace Robot1 { void Func(){ cout << "Robot1::Func" << endl; } void Mode(){ cout << "Robot1::Mode" << endl; } } namespace Robot2 { void Func(){ cout << "Robot2::Func" << endl; } } void Func(){ cout << "::Func" << endl; } namespace Robot3{ namespace Robot4{ namespace Robot5{ void Attack(){ cout << "Robot3~5::Attack" <<endl; } } } } namespace R345 = Robot3::Robot4::Robot5; int main() { PowerOn(); Robot1::Func(); Robot1::Mode(); Robot2::Func(); ::Func(); R345::Attack(); return 0; }
例外
戻り値とは違う形でメソッドから特別なエラーを返す仕組み
- 例外を宣言しているメソッドを呼び出す側では例外を処理するロジックを正しく書いていないとプログラムはエラーになる
- そのまま上位にエラーを伝えるときはメソッドで例外を宣言するだけでよい
Exception.cpp
#include <iostream> #include <fstream> #include <cstdlib> using namespace std; void Open(ifstream& file, const char* filename){ file.open(filename); if(! file.is_open()){ throw "ファイルを開けませんでした!"; //メソッドで例外を宣言すると関数外、上位へエラーが伝わる } } void GetLine(ifstream& file, string& line){ getline(file, line); if (file.fail()){ throw "ファイルから読み込めませんでした!"; } } int main(){ try { //OpenやGetLineで投げられたエラーがここで処理される ifstream file; Open(file, "test.txt"); string line; GetLine(file, line); cout << line << endl; }catch(const char* error){ //char -> intにするとエラーになる(terminate called after throwing an instance of 'char const*') cerr << error << endl; return EXIT_FAILURE; } }
test.txtがない場合の結果:
ファイルを開けませんでした!
test.txtが空の場合の結果:
ファイルから読み込めませんでした!
ガベージコレクション
インスタンスを削除する処理をシステムが自動的に実行する仕組み
参考:めっちゃわかりやすい
5分で分かるガベージコレクションの仕組み | geechs magazine
所感
整理整頓の仕組みがたくさんあるな〜。整理整頓上手になりたい。
参考:
ROSのスクリプト構成を考えてみる
C++編
pattern1 package
構成: func.h , func.cpp, func_node.cpp
func.h
- include <必要なファイル>
- namespaceをパッケージ名で作成
- Funcクラスを作成
- コンストラクタとデストラクタの定義(Public)
- pubやsub,callbackを定義(Private)
- その他、必要な変数や構造体を定義(Private)
ヘッダには一度だけincludeされるよう以下を書いておこう
#ifndef FUNC_HPP_ #define FUNC_HPP_ <contents> #endif
func.cpp
- include <必要なファイル>
- namespace{ } 無名名前空間を作成。このファイルのみで使用する変数や関数を定義する
- namespaceをパッケージ名で作成
- Funcクラスの内容を記述する
- コンストラクタでpubやsubを作成
- RunMainLoopにsFunctionのメインの実行文を記述
void Func::RunMainLoop(){ ros::Rate rate(0.1); while (ros::ok()){ ros::spinOnce(); <Functionの実装> } }
func_node.cpp
#include func.h int main(int argc, char* argv[]){ ros::init(argc, argv, "func"); ros::start() pattern1::Func func; func.RunMainLoop(); return EXIT_SUCCESS; }
boost libraryとは
参考: Boost - C++入門 boost - ROS Wiki BOOST FOREACH - C++入門
auto
#include <iostream> #include <vector> using namespace std; int main(int argc, char const* argv[]) { std::vector<int> v; v.push_back (1); v.push_back (2); v.push_back (3); for (auto x: v) { cout << x << endl; } return 0; }
参考: auto - C++入門 C++11 範囲ベース for ループ 入門
find
指定された値を検索する
#include <algorithm> #include <iostream> #include <vector> int main() { std::vector<int> v = { 3, 1, 4 }; auto result = std::find(v.begin(), v.end(), 1); if (result == v.end()) { std::cout << "not found" << std::endl; } else { std::cout << "found: " << *result << std::endl; } }
1
参考: find - cpprefjp C++日本語リファレンス
ハンドル
参考: C++ - ハンドル
tmuxの設定をいじっていみる
設定方法
.tmux.confに設定を記入
設定が反映されない時
tmuxのプロセスをkillしてから立ち上げる
設定内容
tmux v2.1~ :マウスの設定変わっている shift + 右クリック tmux v2.1からmouse関連の設定が変わった
ubuntu16.04
############## # マウス設定 # ############## set-option -g mouse on # アクティブなウィンドウを目立たせる setw -g window-status-current-fg white setw -g window-status-current-bg red setw -g window-status-current-attr bright ######## # 外観 # ######## # ステータスバーの色を設定する set -g status-fg white set -g status-bg black # ウィンドウリストの色を設定する setw -g window-status-fg cyan setw -g window-status-bg default setw -g window-status-attr dim # アクティブなウィンドウを目立たせる setw -g window-status-current-fg white setw -g window-status-current-bg red setw -g window-status-current-attr bright # ペインボーダーの色を設定する set -g pane-border-fg green set -g pane-border-bg black # アクティブなペインを目立たせる set -g pane-active-border-fg white set -g pane-active-border-bg yellow # コマンドラインの色を設定する set -g message-fg white set -g message-bg black set -g message-attr bright
ubuntu14.04
############## # マウス設定 # ############## # 画面ドラッグ時にコピーモードにする set-option -g mode-mouse on # マウスでペインを選択できるようにする set-option -g mouse-select-pane on # マウスでウィンドウを切り替えられるようにする set-option -g mouse-select-window on # マウスでリサイズできるようにする set-option -g mouse-resize-pane on # アクティブなウィンドウを目立たせる setw -g window-status-current-fg white setw -g window-status-current-bg red setw -g window-status-current-attr bright ######## # 外観 # ######## # ステータスバーの色を設定する set -g status-fg white set -g status-bg black # ウィンドウリストの色を設定する setw -g window-status-fg cyan setw -g window-status-bg default setw -g window-status-attr dim # アクティブなウィンドウを目立たせる setw -g window-status-current-fg white setw -g window-status-current-bg red setw -g window-status-current-attr bright # ペインボーダーの色を設定する set -g pane-border-fg green set -g pane-border-bg black # アクティブなペインを目立たせる set -g pane-active-border-fg white set -g pane-active-border-bg yellow # コマンドラインの色を設定する set -g message-fg white set -g message-bg black set -g message-attr bright
参考:
ペイン関係
- ペイン番号表示・移動
ctrl+b -> q -> 番号
kerasを動かしてみる~その2:CNN~
tensorflowをバックエンドで動かす
.keras/keras.jsonを以下のように書き換え
{ "image_dim_ordering": "tf", "epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow" }
GPUで使う
pip install tensorflow-gpu
(TBD)
CNNのサンプル
GitHub - fchollet/keras: Deep Learning library for Python. Runs on TensorFlow, Theano, or CNTK.
cifar10
from keras.datasets import cifar10
- CIFAR-10は32x32ピクセルのカラー画像のデータセット
- クラスラベルはairplane, automobile, bird, cat, deer, dog, frog, horse, ship, truckの10種類
- 訓練用データ5万枚、テスト用データ1万枚
x_train shape: (50000, 32, 32, 3)
50000 train samples
10000 test samples
y_train shape: (50000, 1)
50000 train samples
10000 test samples
[3] ‘label -> ex: 3 ’
[ 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.] one_hot
DataAugumentation
from keras.preprocessing.image import ImageDataGenerator
参考:画像の前処理 - Keras Documentation
keras-examples/test_datagen3.py at master · aidiary/keras-examples · GitHub
Keras Model
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D
- Sequential : Sequentialモデル - Keras Documentation
- Conv2D : Convolutionalレイヤー - Keras Documentation
一層目のみinput_shape=x_train.shape[1:]のようにinput_shapeの指定がいる。
x_train shape: (50000, 32, 32, 3)の後ろ3つを取り出している。
モデルの保存・読み込み
from keras.models import load_model model.save('my_model.h5') # creates a HDF5 file 'my_model.h5' del model # deletes the existing model # returns a compiled model # identical to the previous one model = load_model('my_model.h5')
参考:[TF]KerasでModelとParameterをLoad/Saveする方法 - Qiita
コード例
'''Train a simple deep CNN on the CIFAR10 small images dataset. GPU run command with Theano backend (with TensorFlow, the GPU is automatically used): THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatx=float32 python cifar10_cnn.py It gets down to 0.65 test logloss in 25 epochs, and down to 0.55 after 50 epochs. (it's still underfitting at that point, though). ''' from __future__ import print_function import keras from keras.datasets import cifar10 from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers import Dense, Dropout, Activation, Flatten from keras.layers import Conv2D, MaxPooling2D from keras.models import load_model import numpy as np batch_size = 32 num_classes = 10 epochs = 2 data_augmentation = True # The data, shuffled and split between train and test sets: (x_train, y_train), (x_test, y_test) = cifar10.load_data() print('x_train shape:', x_train.shape) print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') print('y_train shape:', y_train.shape) print(y_train.shape[0], 'train samples') print(y_test.shape[0], 'test samples') print(y_test[0], 'label -> ex: 3 ') # Convert class vectors to binary class matrices. y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) print(y_test[0], 'one_hot') model = Sequential() model.add(Conv2D(32, (3, 3), padding='same', input_shape=x_train.shape[1:])) model.add(Activation('relu')) model.add(Conv2D(32, (3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(64, (3, 3), padding='same')) model.add(Activation('relu')) model.add(Conv2D(64, (3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(512)) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(num_classes)) model.add(Activation('softmax')) # initiate RMSprop optimizer opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6) # Let's train the model using RMSprop model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 if not data_augmentation: print('Not using data augmentation.') model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(x_test, y_test), shuffle=True) else: print('Using real-time data augmentation.') # This will do preprocessing and realtime data augmentation: datagen = ImageDataGenerator( featurewise_center=False, # set input mean to 0 over the dataset samplewise_center=False, # set each sample mean to 0 featurewise_std_normalization=False, # divide inputs by std of the dataset samplewise_std_normalization=False, # divide each input by its std zca_whitening=False, # apply ZCA whitening rotation_range=0, # randomly rotate images in the range (degrees, 0 to 180) width_shift_range=0.1, # randomly shift images horizontally (fraction of total width) height_shift_range=0.1, # randomly shift images vertically (fraction of total height) horizontal_flip=True, # randomly flip images vertical_flip=False) # randomly flip images # Compute quantities required for feature-wise normalization # (std, mean, and principal components if ZCA whitening is applied). datagen.fit(x_train) # Fit the model on the batches generated by datagen.flow(). model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size), steps_per_epoch=x_train.shape[0] // batch_size, epochs=epochs, validation_data=(x_test, y_test)) """ # save the model model.save('./model.hdf5') """ """ # load model model = load_model('model.hdf5') #loss, acc = model.evaluate(x_test, y_test, verbose=0) #print('Test loss:', loss) #print('Test acc:', acc) # only one test x_test = x_test[0].reshape(1, 32, 32, 3) print(model.predict(x_test)) # predict result = model.predict(x_test) print(np.argmax(result)) """
配列の入れ替え
shape: (1,2,3,4) -> (1,4,2,3)
データ構造
keras -> train shape: (50000, 32, 32, 3)
chainer -> train shape: (50000, 3, 32, 32)
import numpy as np x = np.arange(4*6).reshape(1,2,3,4) print x.shape x = np.swapaxes(x,1,3) y = np.swapaxes(x,1,2) print y.shape
参考: