かえるのプログラミングブログ

プログラミングでつまずいたところとその解決策などを書いていきます。

VOC2007 dataset で遊ぶ① (2019/01/26)

かえるるる(@kaeru_nantoka)です。

今回はかねてより segmentation task に取り組みたいなあ と思っていた私が、手頃なデータ落ちてないかな〜とネットサーフィンをしていたところ tarファイルで 480MB という頑張ったらローカルで云々できそうなデータセットを見つけたので、云々した物語の第一弾です。

それでは、VOC2007データセットで遊ぶ① と称して

VOC2007データセットのダウンロード ~ train_dfの作成 ~ リサイズ ~ img画像と mask画像の可視化

までを残していこうと思います。

ソースコードは ↓ です。

https://github.com/osuossu8/Play_With_VOC2007/blob/master/get_idx_name_and_mk_train_df.ipynb

ちなみに環境は、Google Colab です。

(...いいぱそこんほしい。。。)


参考 URLs

data の準備 :

https://qiita.com/tktktks10/items/0f551aea27d2f62ef708

train_dfの作成:

https://www.kaggle.com/shaojiaxin/u-net-with-simple-resnet-blocks-v2-new-loss



まず、データをここ(http://host.robots.ox.ac.uk/pascal/VOC/voc2012/#devkit)から落としてきます。

次に、tar ファイルを解凍します。

!tar -xvf "/content/drive/My Drive/VOCtrainval_06-Nov-2007.tar"

/content/ 配下に解凍されました。

[in]
import os
os.listdir("/content/VOCdevkit/VOC2007/")

[out]
['SegmentationObject',
 'Annotations',
 'JPEGImages',
 'ImageSets',
 'SegmentationClass']

中身は ↑ のようになっています。 今回使うのは、JPEGImages(元画像), SegmentationObject(マスク画像) の二つです。

これらの配下に、 'hogehoge.jpg' や 'piyopiyo.png' といった形で画像が入っています。

最終的には、画像を pixel の numpy.array に変換して保持します。

Kaggle の塩コンペの kernel を参考に実装していきました。

img_path = "/content/VOCdevkit/VOC2007/JPEGImages"
mask_path = "/content/VOCdevkit/VOC2007/SegmentationObject"
import os

def get_idx_name(path):
  idx = os.listdir(path)
  idx_name = []
  for i in range(len(idx)):
    idx_name.append(os.path.splitext(idx[i])[0])
  return idx_name

まず、画像ファイル名の拡張子以外の部分を抜き出します。↑

[in]
img_idx = get_idx_name("/content/VOCdevkit/VOC2007/JPEGImages")
mask_idx = get_idx_name("/content/VOCdevkit/VOC2007/SegmentationObject")
print(len(img_idx), img_idx[:3])
print(len(mask_idx), mask_idx[:3])

[out]
5011 ['006473', '008023', '009659']
422 ['000661', '005859', '009950']

↑ を見ると、segmentation と対になっている元画像が422枚しかないようです。 segmentation 画像のある元画像を抜き出してみます。

[in]
img_has_mask_idx = set(img_idx) & set(mask_idx)
img_has_mask_idx = list(img_has_mask_idx)

print(len(img_has_mask_idx), sorted(img_has_mask_idx)[:3])
print(len(mask_idx), sorted(mask_idx)[:3])

[out]
422 ['000032', '000033', '000039']
422 ['000032', '000033', '000039']

これで使いたい画像のインデックスを集めることができました。 次にこれをもとに画像を取得して pixelの numpy.arrayにしたものを df[img], df[mask] というカラムに格納します。

まず使うライブラリを宣言して

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import seaborn as sns
sns.set_style("white")

%matplotlib inline

from keras.preprocessing.image import array_to_img, img_to_array, load_img
train_df = pd.DataFrame()
train_df["images"] = [np.array(lod_img(img_path + "/{}.jpg".format(idx))) / 255 for idx in sorted(img_has_mask_idx)[:100]]
train_df["masks"] = [np.array(load_img(mask_path + "/{}.png".format(idx), color_mode="grayscale")) / 255 for idx in sorted(mask_idx)[:100]]

こんな感じになります。

[in]
train_df.images[0].shape, train_df.masks[0].shape

[out]
((281, 500, 3), (281, 500))

このままだと、縦横の長さが異なるので一旦縦に合わせてリサイズします。 コードは、塩コンペのカーネルにあったものを流用しています。

from skimage.transform import resize

img_size_ori = train_df.images[0].shape[0]
img_size_target = 101

def upsample(img):# not used
    if img_size_ori == img_size_target:
        return img
    return resize(img, (img_size_target, img_size_target), mode='constant', preserve_range=True)
    
def downsample(img):# not used
    if img_size_ori == img_size_target:
        return img
    return resize(img, (img_size_ori, img_size_ori), mode='constant', preserve_range=True)
[in]
img_resize = downsample(train_df.images[0])
msk_resize = downsample(train_df.masks[0])

img_resize.shape, msk_resize.shape

[out]
((281, 281, 3), (281, 281))

揃いました。

あとは、plt.imshow()したら終わりです。お疲れ様でした。

plt.subplot(1, 2, 1)
plt.imshow(img_resize)

plt.subplot(1, 2, 2)
plt.imshow(msk_resize)

f:id:kaeru_nantoka_py:20190125032916p:plain


結び

野生のデータを取得して、過去コンペのソースを頼りに欲しい形にデータを整形し、データセットを作ることができました。 train, mask 420枚づつと少々物足りないですが、augmentation などで水増しすることなどを含めて遊んでいこうと思います。

ありがとうございました。

[おまけ] 筆者が、 plt.imshow()と間違えて、plt.plot() してしまった時の写真。

f:id:kaeru_nantoka_py:20190125032815p:plain

おぞましすぎる。。

julia 言語に入門してみた。 (2019/1/11)

かえるるる(@kaeru_nantoka)です。

今回は julia 言語を Jupyter notebook 上で扱えるよう環境構築をしたので備忘として残しておきます。

環境 **

PC : MacBook Air
OS : macOS High Sierra ver 10.13.6

how to **

$ brew cask install julia
$ julia

bash 上で上記コマンドを叩きます。
私の場合は、install した時点で環境変数に登録されていましたので、
すぐに $ Julia でインタラクティブ・セッションに入れました。

julia > ]
(v1.0) pkg > add Conda#master
(v1.0) pkg > add IJulia

julia > のモードに入ったら、] を叩きます。
するとさらにモードが変わるので、残りのコマンドを叩いて完了です。

$ jupyter notebook


f:id:kaeru_nantoka_py:20190111014522p:plain

比べてみる **

julia の特徴はとにかく計算が高速らしいです。

中学校で習うレベルの簡単な計算問題を for 文で回してみました。
まずは、 python

import time
from tqdm import tqdm

start = time.time()

def f(x):
    y = 2 * x + 1
    return 3 * y

for i in tqdm(range(50001)):
    print (f(i))

end = time.time()

print("{} sec".format(end - start))

f:id:kaeru_nantoka_py:20190111023436p:plain

約6.5 sec ... 微妙...100万ループとか気合いの入ったコード書けばよかったですね笑(チキってしまいました。)

それでは、次に julia

@time for i in 1:50000;f(x) = 3(2x+1);println(f(i)); end

f:id:kaeru_nantoka_py:20190111022303p:plain

約1.4 sec 4~5倍も差がついてますね。早いです。

そしてちゃっかり、julia の別な特徴である
「数式をそのままかける(ものもある)」

を盛り込みました。

f:id:kaeru_nantoka_py:20190111024159p:plain

数式チックにかけると言っても、数字がカッコの後ろに来てはいけないなどの簡単なルールがあります。

感想 **

環境構築が簡単 & kaggler だと馴染みの深い人も多かろう Jupyter notebook で実験できるのはとっつきやすいなーという印象でした。

計算の速さを活かして kaggle の前処理なんかに使えていけたらなと思っております。

ちなみに、Jupyter notebook の ju は julia の頭文字らしいです。
https://en.wikipedia.org/wiki/Project_Jupyter

それでは、ありがとうございました。

Confusion Matrix の復習をしてみた。 2018/12/18

かえるるる(@kaeru_nantoka)です。

今回は、私が今朝まで参加していた通称 PLAsTiccコンペ
PLAsTiCC Astronomical Classification | Kaggle)で大変お世話になった、
Confusion Matrix (sklearn.metrics.confusion_matrix — scikit-learn 0.20.1 documentation)

について復習したのでその備忘として書いていこうと思っております。

ソースコードは、私の github に残しているのでよろしければご覧になってください。

https://github.com/osuossu8/myEDAs/blob/master/plasticc/confusion_matrix.ipynb

*****

( i ) Confusion Matrix とはなんぞや

このような図を描画してくれる便利メソッドです。

f:id:kaeru_nantoka_py:20181218225533p:plain
PLAsTiCC コンペでの私の best model の Confusion Matrix

簡単に言うと分類問題で、test label と prediction label とで、何を何に分類しているのかが格子状になっていてひと目でわかる描画メソッドです。

PLAsTiCC コンペは たくさんある星のデータを15種類に分類するのが課題でした。

コンペ中は、
New Confusion matrix | Kaggle

というような discussion スレッドが立ち、上位陣のモデルでは何を正しく分類できており、何を正しく分類するのが難しいのかを知ることができ、大変参考になりました。

( ii ) 動機

今回の執筆の動機は、シンプルに言うとまた使えるように整理しておきたかったからです。
実はこの PLAsTiCC コンペで散々お世話になったこのメソッド、 コンペ期間中はコピペで、中身を理解せずに使用しておりました。
コピペのままじゃあ次につながらぬ。と言うことでおさらいがてらまとめてみようと思った次第です。

( iii ) 本題

はい、今回は定番中の定番、アヤメのデータセットを使って復習してみました。(一度やってみたかった)

アヤメのデータセットは、花弁や茎などの長さといった特徴から 3種類に分類する基本的なデータです。
分類に使用したモデルは XGBoost です。

import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

import matplotlib.pyplot as plt
import seaborn as sns 

import xgboost as xgb

from sklearn import datasets
from sklearn.model_selection import train_test_split

使用するライブラリを import して

# Iris データセットを読み込む
iris = datasets.load_iris()
X, y = iris.data, iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1111)

params = {
        # 多値分類問題
        'objective': 'multiclass',
        # クラス数は 3
        'num_class': 3,
}

# 上記のパラメータでモデルを学習する
clf = xgb.XGBClassifier(**params)
    
clf.fit(X_train, y_train)
    
# テストデータを予測する
y_pred = clf.predict(X_test)

# 精度 (Accuracy) を計算する
from sklearn.metrics import accuracy_score
print(accuracy_score(y_pred,y_test))

accuracy は 0.97 とかでした。

アヤメのデータセットは ndarray の形で与えられているので、DataFrame に変換しておきます。

y_test_df = pd.DataFrame(y_test)
print(y_test_df[0].unique())

y_pred_df = pd.DataFrame(y_pred)
print(y_pred_df[0].unique())


で主役の Confusion Matrix です。

def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')

    print(cm)

    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    plt.tight_layout()


# http://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html

from sklearn.metrics import confusion_matrix

# Compute confusion matrix
cnf_matrix = confusion_matrix(y_test_df, y_pred_df) # 引数に先ほどの df を渡す...(a)
np.set_printoptions(precision=2)

class_names = list(y_pred_df[0].unique()) # 正解ラベルを定義 ...(b)

# Plot non-normalized confusion matrix
plt.figure(figsize=(5,5))
foo = plot_confusion_matrix(cnf_matrix, classes=class_names,normalize=True,
                      title='Confusion matrix') ...(a) (b) を渡す

これで以下のような画像が得られます。

f:id:kaeru_nantoka_py:20181218231632p:plain


1.00 となっている label 0 と label 1 は 100% 正しく分類できており、0.94 となっているところは、label 2
を正しく分類できた確率が 94% , 残りの 0.06 は、正解ラベル 2 のものを間違えて ラベル 1 と予測しちゃったのが 6% あるよ。という見方をします。


( iv ) まとめ

結局ソースコード自体は kernels のものを丸々 パクった 参考にした形になりましたが、
うまく基本データセットで応用できたのできちんと身についたかなと思います。

ありがとうございました。

$gcloud コマンドがどうしても効かない時の tips. 2018/12/18

お久しぶりです。かえるるる(@kaeru_nantoka) です。

今回は、私が2ヶ月ぶりに GCPGPU インスタンスを立てようとした時につまづいたことと、それを脱することができた解決法を記していきます。

根本的な解決法ではないのですが、藁にもすがりたい. そんな時にお役に立てれば幸いです :)

〜今回のケース〜

OS:macOS High Sierra 10.13.6
SDK : google-cloud-sdk-196.0.0-darwin-x86_64.tar
shell : bash

GPU で計算回したいな〜」
「いまはやりのくらうどなるものをいちどさわつてみむ」

はい、このように考えて、

macOS 用のクイックスタート  |  Cloud SDK のドキュメント  |  Google Cloud

ここにたどり着いた方はたくさんいらっしゃると思います。
私もその一人でした。

ここを覗くとありますね、問題の一文が。そう。

f:id:kaeru_nantoka_py:20181218005832p:plain

そして、こう。

f:id:kaeru_nantoka_py:20181218005927p:plain
ローカルの bash で gcloud コマンドが効かなかった図

💢💢ローカルで $gcloud コマンドが効かないんだけど💢💢


path が通っていないんだろうな〜と思い、環境変数を云々してみたものの応答なし。。

環境変数むつかしい・・・

〜〜今回の解決法〜〜

shell までのフルパスでコマンドが叩けます。

f:id:kaeru_nantoka_py:20181218010328p:plain
指定zone の利用可能な設備を確認できるコマンドを叩いた図

よくよく考えたら当たり前なのですが、ちょっと感動しました。

〜おまけ〜

cloud shell というGCP のプラットフォーム上で専用の shell を起動できます。 gcloud, datalab(GCD), gsutil(GCS) などGCPの各サービスで使えるコマンドのパスがデフォルトで通っている shell です。幸せになれます。

以上、ありがとうございました。

「深層学習を用いた株価予測の分析」宮崎・松尾(2017)を読了して

かえるるる(@kaeru_nantoka) です。

 

最近AI関連の技術論文を読むのにハマっておりまして、発見や思ったことを文字として残しておこうかなと思ったので書いていきます。

 

第1弾はこちらです。

https://www.ai-gakkai.or.jp/jsai2017/webprogram/2017/pdf/1112.pdf

以下、当論文 と表記します。

 

概要

画像認識で頻繁に使われる技術を CNN を株価予測に応用してみた。

 

といった内容で考察されてます。

 

発見

1. CNN を画像データ以外に対しても適用できるということ。

 

CNN自体は以前から知っておりました。

この技術を使って 顔認識AI内蔵のLINE BOT を作成し、30人ほどの方に使って頂いたこともあります。

 

一般的に CNN について説明がなされる場合、

当論文の 図1 で示されるような概念図を用いて説明されます。

 

「人間の網膜の仕組みを機械的に再現し、コンピュータに処理させる」という理系的背景がなくても直感的に理解できるもので、私も漏れなくそのように認識しておりました。

 

従って「CNNで株価予測」とはじめて聞いたときは ??? だったのですが、当論文でも言及があるように

i ) 株価の値動き自体を画像データに落とし込む

i i ) 入力データをそのまま画像データと同様に扱いインプットとする

 

というように考えられることを知りました。

 

2. 当論文では、9:00のデータをブレが大きいアウトライナーとして処理しておりました。

 

以前証券会社に勤めていた私はこの点にささやかながら疑問を感じました。

 

株価予測の過去データの有用性は、当論文でも言及があるように市場関係者がテクニカル分析(過去の値動きを参考に経験則で導き出された予測手法)を使用していることから一定の価値があるとされます。

 

午前9時は、寄り付きといい株式の売買が開始される時間です。

 

よって「寄り付きの時間の値動きにブレがある」という事実もまた将来の株価予測を導き出すための1パラメータになり得るのではないか

と考えていたからです。

 

データ分析のプロの知見とかつて市場関係者として勤めていた者の細やかな経験則とで1つの事象に対する考え方の相違がとても新鮮でした。

 

まとめ

技術論文を読むと学びが多いです。

特に、最初に関連研究や研究史に触れた上でその論文のトピックがどうその流れを変化させうるのかが簡略に述べてあります。

また、当該技術の簡単な実装法、比較対象としてどの技術が有用かなどその分野のバックボーンがない私にとっては宝の山のような情報源でした。

 

これを機会にこういった論文を読んでみようと思った方が増えると嬉しいです。

ありがとうございました。

 

Google Cloud Datalb で kaggle の画像コンペ用の画像データを扱えるようにする。 2018/09/28

かえるるる(@kaeru_nantoka)です。

 

今回は、有料のGPUインスタンスが立てられる、 Google Cloud Datalab 環境で

kaggle の画像コンペ用の大容量の画像ファイルを扱えるようにするプロセスについて書いていきます。
以前、無料でGPU を扱える Google Colab で似たようなエントリを書いたのですが、Datalab の GPUインスタンスでは幾分勝手が違いました。ということで備忘として残していきます。

 

今回のゴール **

(写真A)
 f:id:kaeru_nantoka_py:20180928232720p:plain

からの

img = load_img("TGSsalt/train/hoge/fugafuga12345.png")

train_df = pd.read_csv("TGSsalt/train.csv")

で、エラーにならず読み込めるようになることです。

手順 **

1. zip ファイルをドラッグ&ドロップで持ってくる。

2. zip ファイルと同ディレクトリに notebook を立ち上げる。

3. !unzip コマンドでファイルを展開する。

********


1 )
写真A の上部真ん中あたりに、 upload と書かれたところがあります。
ここを押すと ファイルをアップロードできます。

kaggle の画像ファイルは大容量なので、「容量が大きいですよ!」という旨のポップアップが出ますが、それほど時間もかからずアップロードできます。

2 )
今回のポイントです。

最初私は、デフォルトで存在するディレクトリの datalab/notebook/ というところに 新規notebook を立ち上げ、意気揚々と以下のコマンドを叩きました。

../datalab/TGSsalt.zip #画像がたくさん入っているディレクトリを固めた zipファイル

すると「そのようなファイル、ディレクトリはないですよ〜」と言われました。
はい、 パスが通っていないのです。


Google Colab では、drive/My \ Drive というところにマウントされるので、
drive/My \ Drive/hoge/fuga でパスを通すことができました。

ということで根本的な解決策ではないですが、同一ディレクトリ上に notebook を立ち上げて、ことなきを得ました。

3 )

(写真B)
f:id:kaeru_nantoka_py:20180928235548p:plain


写真の通りです。
こちらは Colab に比べると光の速さで(気持ちの問題です笑)展開されました。

まとめ **

実際に画像がうまく読み出せている画面キャプチャはあるのですが、コンペ期間中なので控えておきます。
私と同じ事象ではまったどなたかの一助になれば幸いです。
以上、ありがとうございました。

Happy Kaggling !

Google Cloud Datalab で OpenCV を使えるようにする。 2018/09/28

かえるるる(@kaeru_nantoka)です。

今回は、 Google Cloud Datalab で kaggle の画像コンペに挑戦するにあたって、

import cv2

がエラーになったのでその解決法を残しておきます。

結論 **

以下のコードを実行したら使えるようになりました!

!apt-get update

!apt-get -qq install -y libsm6 libxext6 --allow-unauthenticated && pip install -q -U opencv-python

!apt-get -qq install -y libxrender1 --allow-unauthenticated


open-cv がサードパーティ製のライブラリなために、lib~ からはじまる上記のパッケージたちをインストールしないといけないようです。

同じような理由で heroku の環境構築でも似たような処理をする必要があります。
興味ある方は、以下の記事も見てみてください!

kaeru-nantoka.hatenablog.com


ありがとうございました!