java.lang.OutOfMemoryError: Failed to allocate a 840012 byte allocation with 555120 free bytes and 538KB until OOM

マイナーな話にはなっちゃうんですが。
AndroidのMapboxでマーカーを追加していて、タブレットで200個ぐらいマーカーを生成する画面でOOMが起こってクラッシュしてしまう、という不具合に遭遇しました。

ググると大きなBitmapをいっぱい追加するとこれが起きやすいという話です。

https://stackoverflow.com/questions/477572/strange-out-of-memory-issue-while-loading-an-image-to-a-bitmap-object

Android Developersの公式でも紹介されていますね。

https://developer.android.com/topic/performance/graphics

皆さん、大体ファイルを読み込んでアプリに表示する系でこれが発生しているようですね。

私はBitmapの生成を、Mapboxのマーカーをタップした時に出るウィンドウのために作ってまして、下記のような感じになります。

public static Bitmap generate(@NonNull View view) {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(measureSpec, measureSpec);

int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();

view.layout(0, 0, measuredWidth, measuredHeight);
/Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);

//bitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}

https://docs.mapbox.com/android/maps/examples/symbol-layer-info-window/

コード自体はMapboxの公式サンプルを利用しているだけです。

なので、上述のAndroid DevelopersやStackOverflowにあるような

BitmapFactory.Options

を使ったやり方がどうにもできませんでした…。

なので、

Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);

Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.RGB_565);

に変更しました。

ARGB_8888 

にすると、1ピクセルにつき、4バイト使うらしいです。


RGB_565

にすると、1ピクセルにつき、2バイト使います。

透明部分とかが表現できませんが、しょうがない…。

ちなみに、手っ取り早くマニフェストファイルに

<application android:largeHeap=”true” > </appplication>

ってして回避することもできるようですが、これは機種によってできなかったりするらしく、また敗北感あるのでやめました…。

Tensorのshapeにクエスチョンマークが入る

PythonでKeras+TensorFlowで色々やってまして

input_tensor = Input(shape=(15, 15)) 

とやりまして、input_tensorについて調べると、

Tensor(“input_1:0”, shape=(?, 15, 15), dtype=float32)

となってます。

ふむふむ。Tensor型なのはわかった…。でもshapeにある「はてなマーク」は一体??

と疑問に思いました。

ありがたいことに、StackOverflowに答えがありました。

https://stackoverflow.com/questions/40951602/what-does-the-question-mark-in-tensorflow-shape-mean/40953146#40953146

“It means that first dimension is not fixed in the graph and it can vary between run calls”

というシンプルな答えでした。

最初の次元が決まってないので、これから追加する可能性があるから、?なんだそうです。

WindowsでGitのコンフリクトをTortoise Mergeで解消する

プルリクした瞬間…Not able to merge と出てコンフリクトしまう… それはプログラマにとって悪夢の始まりですよね!!
コンフリクトを解消するのは神経も使うし、間違うと悲しいことになるので、難しい作業です。(>_<)
というわけで、なるべくこの苦痛な「コンフリクトを解消する」作業をうまくやるために、皆さんどうしていますか?

私は、GitのクライアントがSource Tree、コンフリクト解消ツールはTortoise Mergeを使っています。

コマンドラインでどうにかするのもカッコがいいとは思いますが、こういう時は視覚的にわかりやすいのが一番というのが私のポリシーです。(`・ω・´)

まずは、下準備として、TortiseMerge(トートイズマージ:実際にはTortoise SVNをダウンロード・インスコする)をインストールして使えるようにしておきます。
多分ココ↓(私は昔にTortiseSVNをインストールしているので、調べていません、すみません)
https://osdn.net/projects/tortoisesvn/


で、ここで、

「は? TortiseMergeとか、Tortoise SVNとか旧世代の遺物じゃん!なぜ今更そんなの使うのー??そもそもGitのコンフリクトの話でなんでSVN出てくるんだよ!!」

と皆さん思われたことでしょう…。(>_<)

わかる、わかるよ…。

しかし、 TortiseMerge が意外といいんですよ。

・見やすい
・シンプル
・マージするときに重要な「あっちのも使うしこっちのも使う」「こっちのだけ使う」「あっちのを使う」などがボタン操作で簡単
・SVNと関係なく、 Tortise Merge は使える
・無料

そして、最大の理由が私は高解像度モニターを使っているので、WinMergeだと設定などが消えてしまったり字がちいさすぎて使いづらい(>_<) 
ここは最終的には好みもあるでしょうから、高解像度モニタではない人は、WinMergeでもいいんじゃないでしょうか。

本題に戻りまして、TortiseMergeが使えるようになりましたら、SourceTreeの

「ツール」→「オプション」→「Diff」で「外部マージツール」で「TortoiseMerge」を選択しておきます。(下記図参照)

SourceTreeのマージツール設定画面

選べない場合は、「カスタム」を選択して、「Diffコマンド」のところに TortoiseMerge のexeのパス、引数に

「-base:\”$BASE\” -mine:\”$LOCAL\” -theirs:\”$REMOTE\” -merged:\”$MERGED\”」

と入れておきます。

で、コンフリクトしているファイルのサンプルとして、次のようなファイルがあるとします。

①masterブランチにあるphpinfo.phpというファイル

<?php

//テストなの? 新一ー!!
phpinfo();

//test
?>

②developブランチにあるphpinfo.phpというファイル

<?php

//テストだっちゅーの!!!
phpinfo();

//test
?>

というわけで、3行目のコメントの部分がコンフリクトですね。

まずはWeb上のGithubでdevelopからmasterにプルリクを作ります。

下記のように、コンフリクトして、そのままマージできません、とでますね。

Github プルリクエストした時にコンフリクトが生じる画面


Githubにもコンフリクト解消ツールがありますが、ここはいったんSourceTreeに戻ります。
masterブランチに切り替えて、developをマージします。

ここでも、コンフリクトが発生しています、と表示されます。

SourceTreeでのコンフリクトしているファイルの表示

この、エクスクラメーションがついているファイルを右クリックし

「競合を解決」→「外部のマージツールを起動」

とします。すると、TortiseMergeが起動します。

次のような画面になります。赤い部分がコンフリクトです。


TortiseMergeコンフリクトしているファイル

私がTortiseMergeで気に入っているのは、この下の図で赤丸で表示してある、右上の「Use ‘therirs’ text block」という機能たちなのですが、
・相手の変更を使う
・自分の変更を使う
・相手の変更を使った後に自分の変更を使う
・自分の変更を使った後に自分の変更を使う
などができます。一番下にプレビューが出ます。

Use theirsという機能のボタン

今回は、「Use theirs block then mine(相手の変更を使って、それから自分の変更を使う」を使います。

赤くなっている行を選択し、 「Use theirs block then mine 」のボタンをクリックしてください。

次のようになったら、

TortiseMerge マージした画面

これでコンフリクトを解消したことにするため、「Mark as resolved」ボタンをクリックして「Save」をクリックします。

TortiseMergeを終了して、SourceTreeに戻ります。

すると、下記の図のように、エクスクラメーションマークがなくなっています。(注意:何も変更していなくても、外部のマージツールから戻ると、このようになっているので、コンフリクトが解消されたかどうかをSourceTreeが見ているわけではなく、ただ単に 外部のマージツールから戻ると こうなってます。)

修正内容をもう一度確認し。コミットします。

SourceTreeでのマージされたファイルの表示


Githubでも確認すると、下記の図のように

Githubでマージが成功したことを表示する画面

「Successfully merged…」

となっていて、無事にマージされたことがわかります!!

やったね⊂(^-^)⊃

NumPy.add.atなどのユニバーサル関数+at

NumPyについて書くシリーズの続きです。

ユニバーサル関数(ufunc)とは、ベクトル化演算です。いくつもの要素がある中で、一つ一つ処理するよりも、一度に処理したほうが早いですよね。そういうことをやってくれる関数です。

たい焼きを焼くときに、一つ一つ焼いていると大変です。しかし、たい焼き屋さんでは、いくつものたい焼きの穴が開いている鉄板で一度にたくさんのたい焼きをバシッ!!と作りますよね。あんこを足すときも、一度にできて早いですよね。あれのイメージです。

で、今回は、特にそのユニバーサル関数を at と組み合わせた時の動作がちょっとわかりづらかったので書いておきます。

下記の公式サイトにある
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.at.html
例なのですが

import numpy as np

a = np.array([1, 2, 3, 4])
np.add.at(a, [0, 1], 1)
print(a)
#下記が出力されます。
array([2, 3, 3, 4])

これを例にとって説明するとadd.atの

・1番目の引数は処理する配列

・2番目の引数は処理したいインデックス

・3番目の引数は、addしたい数

です。

私はPHPとかJavaとかが長いので、こういう「1を加算する」的な処理はついついfor文とかでループで書いてしまいがちなのですが、速さが違うので、NumPyのユニバーサル関数を使いこなしていきたいと思います!!

Python assertの使い方

Pythonにassertという宣言があり、こんな使い方ができますという紹介です。

めっちゃ簡単な話ではありますが…。

Pythonのコードを見ていると、ちょいちょいassert出てきて、ほげー と思ってたんですよね。

なんというか、assert はテストコード内で使うというイメージ。

しかし、Pythonでは、致命的なエラーなどを起こした場合、プログラムを止めることができ、しかも、それはデバッグ版だけで起こせるので、開発に便利だよ~ という感じです。

print("before")

a = 1
assert a == 2, "2じゃない"

print("after")

上記を実行すると

before
Traceback (most recent call last):
File "G:/ai_delivery/study12.py", line 4, in
assert a == 2, "2じゃない"
AssertionError: 2じゃない

Process finished with exit code 1


ってなります。

assertのところで終了しているので、print(“after”)は実行されません。

んで、開発の時にデバッグするためのものだよ~ という話なのですが、本番の時にこんなエラー起きたら大変!とか、理由を解明するのも「ええい、面倒!!」ということがあれば、次のようにコマンドラインオプション -Oをつけて実行すればAssertionErrorが出ません。

G:\ai_delivery>python -O study12.py
before
after

これは、大文字のO(オー)です。ゼロじゃないよ。