grbl1.1+Arduino CNCシールドV3.5+bCNCを使用中。
BluetoothモジュールおよびbCNCのPendant機能でスマホからもワイヤレス操作可能。
その他、電子工作・プログラミング、機械学習などもやっています。
MacとUbuntuを使用。

CNCマシン全般について:
国内レーザー加工機と中国製レーザー加工機の比較
中国製レーザーダイオードについて
CNCミリングマシンとCNCルーターマシンいろいろ
その他:
利用例や付加機能など:
CNCルーター関係:



*CNCマシンの制作記録は2016/04/10〜の投稿に書いてあります。


2017年7月19日水曜日

Raspberry Pi Zero Wを購入

昨日7/18にようやく日本でもRaspberry Pi Zero Wが販売になりました。やっと技適が通り、これまで海外で売っていたもの(技適なし:技適マークはあるものの、番号がない)とは違うものらしい。

スイッチサイエンスでは、会員登録して入荷通知設定をしておくと上のようなメールが届くシステムになっており、販売日時などは予めわかっていました。7/18の18:00から販売開始でしたが、その時間にログインしてみてもなかなか販売開始にならず、しかもアクセスが集中しているためかほぼ接続できない状況になっていました。アクセスできてもあいかわらず以下のような「この商品は在庫がありません」だけの表示。


このような人気商品がネットショップで発売になる場合、サーバ混雑はよくあることなので、ここは冷静にレスポンスを受け取れるまで何度も再読み込みをしてみました。
18:00開始とは言っても、実際は19:34になってはじめて、商品をカートに追加できるボタンが現れて、ようやくクリック。


どうやらカートには追加されたようでしたが、その後の購入手続きのボタンをクリックすると画面移行後にエラー続出。
以前も似たような経験はしたことがあるので、URLをコピペし再読み込みを繰り返すと、10回に1回くらいの再読込でアクセスできる感じで、次の画面に移行できました(画面移行でエラーがでるといっても、複数買いになってしまうことがあるので「カートへ追加」ボタンなどは何回も押さないほうがいい)。
しかし、購入完了までは何回か画面移行しなければいけなく、その都度移行失敗でエラー画面が出てしまいます。何度もチャレンジして、ようやく支払い画面、もうすでに10分以上はこの手続きのために時間がかかっています。

こんな感じ:
・まず、商品画面の表示(「カートに追加」ボタンがあるかどうか)
・「カートに追加」ボタンを押し、購入手続きへ移行
・購入決定(注文発生)
・支払い画面へ移行
・支払い手続き(Paypal経由のクレジットカード払い)

購入完了までの4〜5回画面移行するたびにエラー画面が現れるので、画面表示されたらそのURLをコピーしておき、次の画面へ移行後エラーが出た場合、前のURLを再入力して再度前画面に戻るか、移行後のURLもコピーしておき、何度もアクセスする感じで、10回に1回くらいの頻度で少しずつ進んで行く感じです。画面移行したら、その画面はキープしておき、また別の画面を用意して元のURLをペーストして再読み込みさせるという感じで、ひとつの画面で先にも進めず、元にも戻れずとはならないように、複数の画面を使い分けるのがいいと思います(とは言っても、こんなアクセス不安定な状況下での注文の機会はあまりありませんが)。
最後のPaypalでの支払いボタンを押すところまで辿りつけたのですが、支払いボタンをクリックした後にまたエラー。これも何度か繰り返し、Paypalアカウントのほうも開いて支払い済みになっているかチェックしてみたものの、まだ支払いが未確認。
そうすると、どうやら登録してあるGmailのほうになにやら返事が来ているようで、みてみると、


このような注文と支払い完了のメールが2通届いていました。
これでどうやら購入できたようです。ようやく安心。
その後Paypalアカウントのほうもチェックしてみると、支払いが発生しており無事購入完了となりました。何度も再読み込みやクリックをしたので、複数支払いが発生していないか心配でしたが大丈夫そうでした。
結局、19:34にカートへ追加の画面が現れて、購入手続きと支払い手続きが完了するまでにエラー画面をくぐりぬけて19:51に購入成立に至りました。どうやら19:30以降の20分程度(アクセス状況が悪い中)で売り切れになったようです。Twitterを見ると、カートに追加はできたけれども、支払い画面でエラーが出て、再度画面を戻るとすでに売り切れ状態になっていて購入できなかったという人も多かったようです。
もしサーバが安定していて、スムースに購入できていれば、5分もたたないうちに売り切れになっていたでしょう。逆にアクセスしにくい状況であったからこそなんとか運良く買うことができたのかもしれません。
もうひとつの販売ショップであるKSYのほうでは、20:00頃でも4320円のセット販売の商品なら売り切れにはなっていませんでしたが、それもいつのまにか売り切れ。
やはり、案の定すぐに売り切れという結末でした。


PimoroniのRaspberry Pi Zero W:
Raspberry Pi Zero Wは、3月頃に発売予定でしたが、技適マークは印刷されてはいるものの番号がまだついておらず、ずっと販売延期になっており、再度新しいタイプ(技適番号付き)を発売するには数ヶ月後になるのではと思っていたので、待ちきれず英国のPimoroniのほうで購入しておりました。
PimoroniのZero Wは技適マークはついているものの、番号まではついていないのでこのままでは正式な技適認証済のものとはならないようです。
最近のPimoroniのZero W(購入当時は送料込みで1970円)は、以下のようにもう技適番号もついているようです。
おそらくしばらくはヤフオクやAmazonで高額転売されると思うのですが、今回購入できなかった場合は、Pimoroni(送料込みで約2000円)で購入すればいいと思います。早ければ1週間程度で届きます。


カメラモジュール:
いずれにせよZero WにカメラモジュールをつけてWifiカメラをつくりたいと思っていたので、

AliExpress.com Product - Raspberry Pi Zero Camera Focal Adjustable Night Vision Camera Module +2 IR Sensor LED Light for RPI Zero 1618円(送料無料)
このような暗視カメラもAliExpressで購入しました。国内でこのようなカメラモジュールはなぜか高い(5MPで3000円くらい、8MPで5000円くらい)。


Raspberry Pi用のカメラモジュールは、いくつか出ていますが、問題はこのフラットケーブルで、Pi3の端子(幅広)とZeroやZero Wの端子(幅細)の幅が違うし(幅変換が必要)、もう少し短いケーブルも欲しかったことから、
この公式のケース(648円)に付属している短いケーブル欲しさのために、これも今回スイッチサイエンスから購入しました(案外このような短い変換ケーブルが売っていないので)。

最初に販売された$5のZeroのほうはWifiがないために、$10のZero Wのほうが圧倒的に便利だろうとZeroは購入しませんでした。
実際にZero Wを使ってみると、Pi3に比べるとスペックは下なので、やはり動きはやや遅いという感じです。モニターをつないで、ブラウザでインターネットをしてみると動画などは少々きついという感じでした。それでも、この小ささでWifiもBLEもついているし、ESP32よりもかなり強力なのではないかと思います(消費電力は高いけれども)。

Zero Wには、MiniUSB端子が2つしかなく、そのうち一つは電源用なので、実際はMiniUSB端子一つしかありません。そのため、キーボードやマウス操作は以前購入したBluetoothキーボード(タッチパッド付き)を使っています。
AliExpress.com Product - Windows PC 59 Keys Ultra Slim Mini Bluetooth Keyboard with Touch Pad Panel RR6V1451円(送料込み)
USBハブがなければ、普通のUSBキーボードとマウスを両方同時に接続することができません。この部分がZero Wの不便な点ですが、以下のVNCを使えばいいかと。

VNCによる遠隔操作:
そもそもZero Wにはモニターやキーボードを直接接続せずに、パソコンからVNCを使ってWifi経由で遠隔操作したほうが使いやすいと思います。そのためWifiのないZeroではなく、すぐにVNC接続可能なZero Wのほうが便利という感じです。
このようにパソコンにVNC Viewerをインストールし、Zero Wのほうでも設定しておけばZero WのIPアドレスにアクセスして操作できます。

パソコン(MacBook Pro)の画面上に現れたZero Wの画面。
この状態でパソコンからZero Wを扱うことができます。最近のPIXELをZero Wにインストールしておけば、VNCは標準装備されていたと思うので、すぐに使えると思います。
「Raspberry Piの設定」画面内でVNCを有効にしておけば使えるようになります。ただし、最初だけこの設定をモニタとつないで設定しなければいけなかったような。

各種サイズ比較:
左から、18650電池ボックス(USB5V出力)、100均単3電池ボックス(USB5V出力/改造:スイッチ付き)、Zero W、ESP32、ESP8266。
Zero W(65mm x 30mm)は、ESP32より少し大きいのですが、それでもこのスペックにしてはかなり小さい感じです。


ということで数日中には、この変換ケーブルつき公式ケースとともに技適認証済みZero Wが届くと思うので、Wifiカメラの実験をしてみようかと考えています。


追記(現物到着):
7/18の注文から2日後の7/20には、Raspberry Pi Zero Wが到着しました。
さっそく中身を確認してみると、
上のほうは少し前にPimoroniで購入したもの(技適マークはあるものの番号がない)。
そして、下のほうが今回スイッチサイエンスで購入したZero W 。新しいタイプが届くのかと思いきや、技適マークと番号がシールで貼られているタイプのものでした。
最初の国内ロットは、このタイプなのかもしれません。
スイッチサイエンスのページに、このシールについて書いてありましたが、このシールは販売店や購入者が勝手に貼ってはいけないらしい。ハードウェア的な上では、シール以外は何ら変わらない感じで、このシールを貼るだけで済んだのかと少々疑問。当然、このシールの偽造は違法行為となるので、こんなシールであっても重要らしい(苦肉の策という感じ)。
ということで、あまり新鮮味は感じませんでしたが、無事届いたのでよかったです。

そして公式ケース(カメラ用の短いフラットケーブル付き)はというと、
こんな感じでカメラと接続してケースに収納してみました。赤いケースに対して、白い蓋が3種類ついています。カメラは以前AliExpressで購入したもの、そして下に見えるのがカメラに付属していた150mmフラットケーブル。

公式ケースに付属していた短いフラットケーブルはコンパクトにまとまりそうでいいのですが、ケースやZero W本体に対してカメラレンズがどっち向きになるかということが問題。
このカメラの場合はこの状態でレンズが上向きなので、フラットケーブルを折り曲げると、白い蓋のほうには向かず、裏側に向いてしまいます。カメラによっても、基板の裏側にフラットケーブル・コネクタがついているものもあるようで、その場合はレンズは逆向きになるというわけです。カメラを購入する場合は、この向きに注意したほうがよさそうです。
そもそも、このカメラはレンズが大きいのでカメラ用の穴がついている白い蓋には合いません。このケースを使うならば、仕方なくこのように裏側にまわして使うしかないでしょう。幸い、このカメラモジュールの基板の裏面には何も実装されておらず、ただの平面なのでそのまま両面テープなどでも固定できそうです。
単に短いフラットケーブルが欲しかったためにこのケースを購入したので、ケース自体は使うかどうかわかりませんが、せっかくあるので使ったほうがいいかと。

関連:

2017年7月3日月曜日

AliExpressのBluetoothマウス

以前、AliExpressで注文したBluetoothマウスが配送されなかったため、Open Disputeで全額返金してもらい、再度新たなBluetoothマウスを注文しました。今回は、約2週間で無事届きました。
安っぽい(378円送料無料)ので大丈夫かなと思いましたが、一応機能しています。
左がこれまで使っていたワイヤレスマウス(USBドングル付き)でBluetoothではありません。そして、右が今回届いたBluetoothマウス。こちらはBluetoothなのでUSBドングルなしです。
機能的には、左右クリック、スクロールホイール(中クリック可)、マウス移動解像度変更用のボタンもスクロールホイールの後方(上画像では上方)についていました。押すと、3段階:800/1200/1600DPIに切り替えられます。
Bluetoothペアリングは、左右中(ホイール)を3〜5秒ほど同時押しするとパソコン側が認識してくれます。

AliExpress.com Product - 1600 DPI Bluetooth BT 3.0 Wireless Mouse for Android Phone Computers Notebooks Tablet Office Gaming PC Mouse Mini Mice Newest381円(送料無料)
USBドングル付きのワイヤレスマウスはBluetoothマウスより安いのですが、いちいちドングルをパソコンに差し込まないといけないのと、USBポートが一つ埋まってしまうことからBluetoothにしたというわけです。その他、Raspberry PiにもBluetooth経由で使えます。


AliExpressの一番安いBluetoothマウスだと、だいたいこんな感じのものです。Appleのマウスを真似たような薄っぺらい形状をしています。持ちにくいかと思いましたが、特にそんなこともありませんでした。


裏面を見ると、今までのドングル付きワイヤレスマウスは単三乾電池1本でしたが、今回のBluetoothマウスは単四乾電池2本です。LEDは赤。裏面にON/OFFスイッチ。左のドングル付きのワイヤレスマウスは、付属ドングルをマウス裏面に差し込んで収納することができますが、右側のBluetoothマウスにも似たような隙間が設けられています。これは、おそらくこの形状と同じマウスでドングル付きのものがあるからだと思います。以下。


AliExpress.com Product - New 1600 DPI USB Optical Wireless Computer Mouse 2.4G Receiver Super Slim Mouse For PC Laptop Desktop318円(送料無料)
形状は同じだけれどもUSBドングル付きのワイヤレスマウスであって、Bluetoothではないタイプ。その分、やや安い(とは言ってもあまり大差ない)。もしBluetoothマウスが欲しいと言う場合は、値段もあまりかわらないので注意したほうがいいでしょう。
このタイプはAmazonでも似たような値段で売っています。以下。


Posted at 2017.7.3
スへの 2.4G超薄型ワイヤレスマウス 2.4Gスリムなワイヤレスマウス
販売価格 ¥339
(2017年7月3日0時5分時点の価格)
Posted at 2017.7.3
Lovoski  Win 7 Mac Android Tablet PC 用 Bluetooth 1600DPI マウス
Lovoski
販売価格 ¥660
(2017年7月3日0時8分時点の価格)

2017年6月9日金曜日

AliExpressのトラブル(その2)

以前、AliExpressで注文した商品が結局届かなくて払い戻ししてもらいましたが、また違ったトラブルがありました。あいかわらず、数百円程度の電子パーツなどをよく注文しており、もう100回以上なにかしら注文しています。実はここ最近で3回ほどトラブルがありました。

(1)商品が期日内に届かなかった(再配送で解決済)
(2)商品のスペックが違う(全額返金済み/商品は返品せず)
(3)商品が期日内に届かない(現在連絡中、追記:結局Open Disputeで返金)

という感じです。
以下順に書いていきます。


(1)商品が期日内に届かなかった場合:
まずは以下のようなUSB接続可能な小型マイクを注文しました。
AliExpress.com Product - Portable Studio Speech Super Mini USB 2.0 Microphone MIC Audio Adapter Driver Free for MSN PC Notebook Lectures Teaching 202円(送料込み)このショップで購入したわけではないのですが、当時の購入金額は159円(送料込み)でした。3/17に注文して約2ヶ月の期日が過ぎても届かないため、まずはショップにメールしました。今回は特別急いでいなかったので(というよりも注文してから2ヶ月も経ってしまい、代替のUSBマイクを使用することにしたため)、いきなりOpen Disputeをせずに連絡してみることにしました。ちなみに、トラッキング状況は以下のような感じで、途中で止まっているように見えます。配送中に紛失してしまったのかどうかはわかりません。

これもまた一番安い通常郵便で配送されているために、きちんとしたトラッキングサービスはカバーされていないはずなので、そもそもあまり当てになりません。もしきちんとしたトラッキングサービスにするには、以下のような輸送オプションがあり、141円上乗せすればAir Mailなのでトラッキングならびに受取り確認(要ハンコ)になります。しかし、今回は安い買い物なのでわざわざそこまではしません。

そのときのやりとりが以下です(やりとりは下から始まって上へ)。

やりとりの内容を書くと、Me:「まだ届いてないけど、返金するためOpen Disputeしていいですか?」Shop:「Open Disputeはしないで下さい。新しいの送るかPaypal経由で返金もできます。」Me:「じゃ、新しいの送って下さい」Shop:「OK、すぐに手配します」Me:「送る時教えてね。今回トラッキング番号とかある?」Shop:「新しいトラッキング番号にしておくので安心してください」という感じでやりとりは進んで、
Shop:「新しいのを送りました。トラッキング番号は〜です。遅れてすみません。なにかあれば連絡下さい。」という感じで、商品を梱包した状態の写真を送ってきてくれたので、大丈夫だろうと信じて、これでやりとり終了。あとはちゃんと届くかどうか。そして、約2週間後無事届きました(いわゆる通常輸送にかかる時間で)。結局、注文して届くまでから2ヶ月半くらいかかったというわけです。
追記:実は、最初に注文したときのUSBマイクが、約4ヶ月後に届きました。つまり、最終的には合計2個届いたということになります。封筒にスタンプされた日時を確認すると、注文後約3ヶ月半くらい中国国内の集配センターのようなところにあったようです。封筒(小包)が10cm角ほどしかなく小さいので、一時的にどこかに紛れ込んで行方不明になっていたのかもしれません。

(2)の商品のスペックが違った場合:リチウム充電池18650です。もともと怪しいのはわかっていたのですが、試しに注文してみたという感じです。
AliExpress.com Product - 2PCS 3.7 V 4200mAh 18650 Battery batteries batteria lithium Li Ion Rechargeable Large Capacity T6 Flashlight free shipping 404円(2本:送料無料)これは4200mAhもあると書かれているリチウム充電池です。この容量に対して一本約200円という値段(安すぎ)。この手の容量をごまかしている18650リチウム充電池は沢山あるようです。以下は、Youtubeで容量を検証している動画です。こんな動画が沢山あります。

今回注文したものはMick Tick 18650で、注文時の価格は2本で399円でした。2週間程度で届いたので配送においては問題ありませんでした。容量が怪しいので、受け取ってもすぐに受取ボタンを押さずに、以下の充電器で計測してみました。
AliExpress.com Product - Original XTAR VC2 2 Slots 1A Current Universal Intelligent USB Battery Charger with LCD Display for 3.6V / 3.7V Li-ion 18650 1566円(送料無料)この充電器では、充電した分のmAhを数値で表示してくれます。なので、いったんバッテリーを放電してから充電してみました。
結果はこの通りです↑。左側が539mAh、右が443mAh。Youtubeの動画などでも、偽物はだいたい500mAhくらいしかないようです。案の定、今回のバッテリーも同様でした。ついでに重さも計測してみると、

左が24.9g、右が24.5gです。きちんとしたものならば、40g以上あるそうです。
これも動画にあったような偽物の特徴と一致しています。

ということで、今回は問答無用でOpen Disputeボタンを押して、これらの画像も証拠写真として添付し、早速クレームをつけました。
まずは、先程の計測結果内容を書き、全然4200mAhではないので、399円中の350円を返金しろと(画像も添えて)。返品すると送料などかかってしまうため、一部返金ということにしました。
すると数日後に以下のような返信。
Disputeする理由を「商品のキャパシティーが違うため」を選んでいたのですが、ショップ側は「買い手の個人的な理由で」に変更して欲しいとのこと。「注文したけど、思っていたものと違うため」というような理由でキャンセルするということにしてくれれば、返金しますと書いてありました。
このことから察すると、ショップとしても理由によってはAliExpressから何らかのペナルティを受けてしまうのを恐れているのでしょう。
返金してくれるということなので、ためしに言われたとおりにDispute理由を変更し、ついでに399円全額返金希望にしました。

「言われたとおり変更したよ」とメールでも送っておき、そうするとショップ側はこの条件を受け入れたようで無事解決。
ショップは「返金手続きしておきました。悪い評価しないでね。」という控えめな姿勢のメール。

結果としては399円支払った分、全額返金。そして18650のリチウム充電池2本(実際の容量は500mAh前後)は返品不要となりました。
ちなみに、単3アルカリ電池ですら約1000mAhあるらしいので、500mAというのはマンガン電池程度という感じです。ちょっとしたものに使うのならいいけれども、あまりにも容量が少なすぎです。
ということから、18650などのリチウム充電池を購入する際は注意が必要です。やはり日本製が高価ではあるけれどもいいのかもしれません。
トラブルはないほうがいいですが、もしこういうトラブルがあってもAliExpressのシステムのせいか、クレームつければ一応きちんと対応してくれます。


(3)の場合:これもまた期限すぎても届かない(もう慣れたかも)
Bluetoothではないワイヤレスマウスもありますが、USBドングルをつけるのは面倒なのでBluetoothのマウスを探していたところ、Amazonだと1000円くらいするのがAliExpressで345円だったので注文してみました。

AliExpress.com Product - Ergonomic Wireless Bluetooth 3.0 mini Optical Computer Mouse 6 Buttons Mice 1600DPI for laptopTablet PC 10M Working distance 656円(送料無料)
注文したのは、このショップのものではないのですが、今はなぜか全般的にBluetoothマウスはAliExpressで650円以上します。当時注文したのは345円でしたが、セールとかだったのでしょうか?このマウスもまた期限(2ヶ月)が過ぎても届かないので、とりあえずメール問い合わせしている最中。いきなりOpen Disputeしてもいいのですが、返金扱いにして新たにBluetoothマウスを購入することになると650円になってしまうので、なんとか345円でそのままもう一度同じマウスを送ってもらったほうがいいのではないかということです。

あいかわらず通常郵便なのでトラッキングサービスはカバーされていません。一応配送状況はこんな感じで出ていますが、4/8以降は途切れたままです。いままでの経験からすると、この状態でも届くものは届くのですが、やはり2ヶ月以上届かないというのは、もう届かないと思ったほうがいいと思います。いままでで、遅くても6週間くらいでした。通常なら2〜3週間。というわけで、これは現在進行中です。
追記:その後、数回のメールのやりとりをして、最終的にはOpen Disputeで返金手続きしました。ということで、また新たにBluetoothマウス(別の製品:378円)を注文し直しました。
AliExpress.com Product - 1600 DPI Bluetooth BT 3.0 Wireless Mouse for Android Phone Computers Notebooks Tablet Office Gaming PC Mouse Mini Mice Newest


まとめ:スペックが怪しい商品、動作確認が必要そうな商品は、受け取ってもすぐに受取ボタンを押さずに、実際に電源につないで動かしてみたほうがいいと思います。そして問題があれば、受取ボタンを押す前にショップへメール連絡したほうがいいでしょう(できれば強気で)。ショップとしても客からクレームつくのは嫌だと思うので、それなりの対応をしてくれると思います。Open Disputeは、まずお互いの条件を出し合い、それでOKならそのまま解決へと向かいますが、どちらかが納得行かない場合は、つぎの段階としてAliExpressが介入してくれるようです。AliExpressメンバーレベルというのがあって、A3レベルだと25ドルまではすぐに返金してくれるようです。A4レベルなら100ドルまで。買い物すればするほどレベルはあがって、様々な特典が得られるようになります。ショップとしてもペナルティにつながるようなことにはなりたくないはずなので(出店禁止とか)、きちんと証拠写真や要望を述べれば大丈夫かと思います。あまりぐだぐだと「このような場合どうしたらいいでしょうか?」というようなお伺いをたてないほうがいいと思います。単純に、「商品が〜だったので(証拠写真付きで)、全額返金希望(あるいは一部返金希望)」と書いた方がいいと思います。
いまのところ110回のショッピングで4回のトラブルがあったということになります。返金や再配送というかたちで解決しているので、特に問題ないという感じです。これにこりてAliExpressではショッピングしなくなるかというと、そういうわけでもありません。AliExpressの場合、2ヶ月経たないとわからないというのが面倒なので、すぐに欲しいものであれば多少高くてもAmazonのほうがいいかもしれません。ただしこのような部品類などはAmazonでも中国からの配送となるので、内容的には同じことだと思います。同じ中国からでも、Amazonのほうが若干早く届くような気がしますが、たまにものすごく遅いときもありました。なので、中国からの配送品に関しては、時間についてはあまり期待しないほうがよさそうです。2週間でつけば早いほうで、1ヶ月くらいは待つつもりでいたほうがいいかもしれません。

2017年6月2日金曜日

線形回帰のプログラミング(その2):勾配降下法

前回、グラフ平面上の複数の点(データ群)に対して直線フィッティングをするために最小二乗法を試してみましたが、今回は勾配降下法によるプログラムです。
最小二乗法は、公式に数値を入れるとすぐに答えがでてくるような感じでしたが、勾配降下法は直線の式に動的に近づいていく求め方なので、コンピューターを利用した求め方に、より適しているような気がします。公式によって一発で答えを導き出すというよりも、経験的に答えを探しにいくという感じでしょうか。

黄直線:勾配降下法、赤直線:最小二乗法

とはいっても、やはり公式があるようで、前回同様求めたい直線の式を

y = m * x + b

とすれば、

Error(m, b) = 1/n * Σ((m * xi + b) - yi)^2

が、求めたい式と暫定的な式とのmとbのトータルの誤差を表しているようです。Σは、i=1からi=nまでの合計値(for文上では、i=0からi=n-1まで)。
式中の (m * xi + b) - yi は、m * xi + bで求めたyの値から、ある点のyiを差し引いているので、その差が誤差(Error)になるというのがわかります。二乗しているのは、前回の最小二乗法のように符号を+にするということですが、そもそも最終的な目的が、誤差の最小化なので二乗してあっても問題ないということらしいです。
1/nのnは点の数なので、Σで合計したエラー値をnで割ることで平均値が得られるという感じでしょうか。
最終的には、このError(誤差)が0に近づくようにmとbを探していけばいいので、そのためにはこのErrorのグラフ上の傾き(接線)を調べると、式中のΣ以降の部分である

((m * xi + b) - yi)^2

を微分して接線(x,y地点の傾き)を調べると

2*((m * xi + b) - yi)

となり、求めたいmとbについての偏微分(変化率)は

Δm = -2/n * Σ xi * ((m * xi + b) - yi)
Δb = -2/n * Σ (m * xi + b) - yi

となって、このΔmとΔbをプログラム上で加算(更新)していくことで、徐々に求めたい式に近づいていくという方法のようです。
暫定的な直線の式にxとyの値を代入して誤差を求めて、その誤差が0になるようにmとbを更新していくというイメージはなんとなく分かるのですが、実際計算上でどのようにそうなっていくのか?このあたりを今回もプログラミングを通して実感できないかという試みです。
数式だけだと分かりにくいのですが、プログラミングでは今回の値に前回の値を再代入して、それを繰り返して徐々にある目標の値に近づいていくという方法はよくあるので、今回もそんなイメージで考えています。

勾配降下法においては、一発で答えを導くわけではないので、学習率という変数が登場してくるようです。少しづつ求めたい値に近づくために、オーバーシュートしないように0.1や0.01を掛けて小刻みにステップさせる係数のようなものだと思います。
さきほどのΔmとΔbの偏微分の方程式を書くと(今回もProcessingを使用)、

float m = 0;
float b = 0;
float learningRate = 0.1;
float db = 0;
float dm = 0;
for(int i = 0; i < x.length; i++){
    dm += x[i] * ((m * x[i] + b) - y[i]);
    db += (m * x[i] + b) - y[i];
}

m -= 2.0/x.length * dm * learningRate;
b -= 2.0/x.length * db * learningRate;

こんな感じになります。ΔmとΔbはdmとdb、学習率はlearningRate=0.1、for文で点の個数分繰り返しΔmとΔbの加算処理をしています。最終的なmとbは、学習率0.1を掛けたΔmとΔbと今回のmとbとの差分を差し引いて、次回また計算し直して徐々に求めたいmとbに近づいていくというプロセスです。偏微分の方程式があるため、それに従って計算してしまえばいいので、今回は結構短いコードでmとbを求めていくことができます。
しかし、最後に求めたmとbの式をよく見ると、適当に決めた学習率(今回の場合0.1)を掛けているので、

m -= dm * learningRate;
b -= db * learningRate;

のように式中の2.0/x.lengthを消してしまっても、あまり大差なさそうです。今回は方程式のまま書いてみましたが、計算をシンプルにするには、learningRateに係数を含ませてもいいと思います。
あるいは、もっと式をシンプルにすれば、

float m = 0;
float b = 0;
float learningRate = 0.1;
for(int i = 0; i < x.length; i++){
    float error = y[i] - (m * x[i] + b);
    m += error * x[i] * learningRate;
    b += error * learningRate;
}

とするだけでもいいのかもしれません。
式中のerrorは、実際のy[i]の値からm*x[i]+bで求めたyの値(もともとy=m*x+bという関係なので)を差し引いた誤差です。
結局は、learingRateで挙動を調整することができるので、ここまで変えてしまっても問題なさそうです。


以下が今回のプログラム(Processing/Processing.js)。前回同様に、以下の空のグラフ上の任意位置をクリックすると点が追加されます。複数の点(2点以上)に対する直線が現れます。 赤の直線は前回の最小二乗法、黄色の直線が今回の勾配降下法によるものです。 点の数や位置によっては、微妙に最小二乗法と勾配降下法の結果がずれることがあります。求め方の違いからくるためなのでしょうか?ブラウザリロードで初期化します。

表示が変な場合(線が点滅するなど)は、前回(一つ前の投稿)のページ上のプログラムと干渉しあっているために起こると思われます。 そうならないようにするためには、この投稿だけのページに切り替えるといいと思います。ここをクリックでこの投稿だけのページへ移動



以下が、全体のコード。
前回と少し違うのは、画面サイズ400x400を一旦0〜1.0に正規化してあります。つまり座標(200,200)の位置をクリックすれば、プログラム内部では(0.5,0.5)という値に相当します。0~1.0で計算しておいて(そうしないと計算の際に数値が溢れてしまったので)、その後画面表示するときは、再度400x400のフォーマットに変換し直しています。

float[] x = new float[0];
float[] y = new float[0];
float m_gd = 0; //勾配降下法のmの変数
float b_gd = 1; //勾配降下法のbの変数
float m_ls = 0; //最小二乗法にmの変数
float b_ls = 0; //最小二乗法にbの変数

void setup(){
  size(400,400);
  rectMode(CORNERS);
}

void draw(){
  background(51); 
  stroke(255);
  fill(255);
  for(int i = 0; i < x.length; i++){//点の描画
    ellipse(x[i]*width,y[i]*height,4,4);
  }
  
  if(x.length > 1){//点が2点以上の場合
    leastSquare();
    gradientDescend();
  }
}

void gradientDescend(){//勾配降下法
  float learningRate = 0.1;
  float db = 0;
  float dm = 0;
  for(int i = 0; i < x.length; i++){  
    dm += x[i] * ((m_gd * x[i] + b_gd) - y[i]);
    db += (m_gd * x[i] + b_gd) - y[i];
  }
  
  m_gd -= 2.0/x.length * dm * learningRate;
  b_gd -= 2.0/x.length * db * learningRate;

  stroke(255,255,0);
  drawLine(m_gd, b_gd);  //勾配降下法による直線描画
}

void leastSquare(){//最小二乗法
  float xsum = 0;
  float ysum = 0;
  for(int i = 0; i < x.length; i++){
    xsum += x[i];
    ysum += y[i];
  }  
  float xmean = xsum / x.length;
  float ymean = ysum / y.length;  
  float xy = 0;
  float xx = 0;
  for(int i = 0; i < x.length; i++){
    xy += (x[i] - xmean) * (y[i] - ymean);
    xx += (x[i] - xmean) * (x[i] - xmean);    
  }  
  m_ls = xy / xx;
  b_ls = ymean - m_ls * xmean;
  
  stroke(255,0,0);
  drawLine(m_ls, b_ls); //最小二乗法による直線描画
}

void drawLine(float M, float B){//mとbによる直線描画
  float x1 = 0;
  float y1 = M * x1 + B;
  float x2 = 1;
  float y2 = M * x2 + B;  
  line(x1 * width, y1 * height, x2 * width, y2 * height);
}

void mousePressed(){//クリックするごとに新たな座標値を配列に追加
  x = append(x, 1.0 * mouseX / width); //0〜1.0に正規化して配列に格納
  y = append(y, 1.0 * mouseY / height);
}


学習率:learningRateは0.1に設定してありますが、0.01に落としてもいいかもしれません。ただその場合、動きはゆっくりになります。
点の数が少なすぎたり、互いに点が近すぎると、最小二乗法による直線(赤)と勾配降下法による直線(黄)とに微妙な違いがでてくるようです。学習率(単位ステップ数)を調整すればいいのかもしれませんが、そのへんについては検討中。

今回の最小二乗法と勾配降下法については、数学的に証明可能なレベルまで理解したり、ここで登場してくる方程式を自ら導き出せるほど完全に理解しているというわけではないのですが、プログラミングにおけるライブラリのように、ライブラリをつくるのは大変だけれども、ある程度の仕組みを理解して使いこなすということはできると思います。画像認識のOpenCVあるいはPID制御やFFT(高速フーリエ変換)などのライブラリもそんな感じです。まったく理解していないとライブラリを使うこともできませんが、そこそこ理解していれば、これまで計算できなかったことが可能になるので、その程度は勉強しておいたほうがいいのかもしれません。もしくは、完全な理解を得るには時間がかかってしまうので(そもそもその分野の専門家でもないので)、深い理解はとりあえずはスキップし、まずは使い方を身につけて、使っているうちに徐々にその仕組がわかってくるという順番のほうがいいのかもしれません(知識欲のために理解しようとしているわけではないので)。

続き:
CourseraのMachine LearningコースとDeep Learningコース

2017年5月31日水曜日

線形回帰のプログラミング

線形回帰(Linear Regression)を理解するためにプログラム(Processingを使用)を組んでみました。相変わらずこのような数学的な内容はWikipediaの説明ではわかりにくいので(もうすでに理解している人のために書いている内容であって、分からない人が理解できるような説明にはなっていない)、プログラミングすれば理解が深まるかもしれないと思って試してみました。

センサーを使ってデータを集めた際に、以下のようなグラフになることがあります。これらのドット分布を簡単な数式(今回の場合は単純な直線の式:赤い直線)に置き換えることができないかということです。


直線の一次式は、

y = m*x + b

で表せるので、要はmの傾きとbの値(x=0の時のyの値)を求めることができればいいというわけです。
どうやら公式があるようで、

m = Σ(Xi - Xmean) * (Yi - Ymean) / Σ(Xi - Xmean) *(Xi - Xmean)
b = Ymean - m*Xmean

となるようです(Σはn=0からn-1までの合計値)。
Xiはある点のXの値、XmeanはすべてのXの点の平均値、Yについても同様。
ただし、この式だとわかりにくいので、Σを使わないで表せば、

それぞれのX座標値:X0、X1、X2・・・Xn-1
それぞれのY座標値:Y0、Y1、Y2・・・Yn-1

とすれば(n個の点があるという前提)、
プログラム上のfor文では、for(int i=0; i<n; i++)となるのでn-1まで、

(X0-X平均値)*(Y0-Y平均値)+(X1-X平均値)*(Y1-Y平均値)+(X1-X平均値)*(Y1-Y平均値)・・・
+(Xn-1-X平均値)*(Yn-1-Y平均値)

の合計と、

(X0-X平均値)*(X0-X平均値)+(X1-X平均値)*(X1-X平均値)+(X2-X平均値)*(X2-X平均値)・・・
+(Xn-1-X平均値)*(Xn-1-X平均値)

の合計を求めて、
上の合計を下の合計で割ればmが求まり、
bについては、

b = Y平均値 - m*X平均値

で直線の式がでてくるようです。
ある式をn=0からi=n-1まで計算していくには、プログラミングではfor文を使えばいいので簡単です。
ただし、方法としてはこれもまたよくでてくる最小二乗法というものです。この最小二乗法が解法のテクニックだと思うのですが、求めたい直線と各点のyの値とのズレをすべて合計して(さらにプラスマイナスの符号をなくすために二乗する)、その差を少なくすればいいというのは直感的に分かるので、そのあたりをプログラムを通して理解しようとしてみました。
複数ある点の平均値を求めるので、そこが点分布の重心となり、かならずこの重心を通るような線となるようです。




空白のグラフ(上)がありますが(上に画面が現れない場合や表示が変な場合はこちらをクリック)、任意の位置をクリックすると点が追加されていきます(Processing/Processing.jsで書いています)。
複数点を打っていくと、その分布する点に対する一次式の直線が計算により求められるというプログラムです。当然二点打てば、その二点を通る直線ができるわけですが、三点目を少しずらしたところに打てば、その三点以上の点分布に対する直線式が出てきます。異なる位置に点を追加していくことで、微妙に線の傾きが変化していきます。
直線は点分布の重心を必ず通ることから、二点打ったあとにその中点を打ち、その上下(y軸と平行に)に等間隔でさらに二点打てば、傾きは変化しないということになります。こうやって、点を追加していくことで、傾きが変化したりしなかったりという性質が分かるので理解が深まります。
*リセット機能はプログラムに含まれていないので、ブラウザでリロードすれば初期化されます。

以下が、Processingによるコード。


//クリックで追加されていく点の座標の配列を用意
int[] x = new int[0]; 
int[] y = new int[0];

void setup(){
  size(400,400);
}

void draw(){
  background(51);

  //xとyの平均値を求める
  int xsum = 0; //xの合計値の変数
  int ysum = 0; //yの合計値の変数
  fill(200);
  stroke(200);
  for(int i = 0; i < x.length; i++){//点の数だけ合計値を求める
    xsum += x[i];
    ysum += y[i];
    ellipse(x[i],y[i],4,4);//各点の描画
  }
  float xmean = 1.0 * xsum / x.length; //xの平均値
  float ymean = 1.0 * ysum / y.length; //yの平均値

  //公式を使って計算する
  float xy = 0; //公式の分子の変数
  float xx = 0; //公式の分母の変数
  for(int i = 0; i < x.length; i++){
    xy += (x[i]-xmean)*(y[i]-ymean); //分子の加算
    xx += (x[i]-xmean)*(x[i]-xmean); //分母の加算
  }
  
  float m = xy / xx; //上記公式からmを求める
  float b = ymean - m * xmean; //公式で求めたmと各平均値からbを求める
  float x1 = 0; //グラフ左端x=0のとき
  float y1 = m * x1 + b; //x=0のときのyの値、結果y1= bとなる
  float x2 = width;  //グラフ右端x=画面幅のとき
  float y2 = m * x2 + b; //x=画面幅のときのyの値、mとbは求まっているのでy2も求まる
  stroke(255,0,0);
  line(x1,y1,x2,y2); //直線を描く
}

//マウスクリックするごとに配列に新たな座標を加える
void mousePressed(){ 
  x = append(x, mouseX); 
  y = append(y, mouseY);
}

プログラミングにおけるY座標は下向きに+ですが、mにマイナスをかけて、height-bとすれば、Y座標上向きを+にすることができます(今回は数値表現していないため省略)。

ネットなどに書いてある線形回帰の説明だと数式だけで数学的に記述されているので、わかりにくいのですが、こうやってプログラミングすることで、どのように計算しているのか理解が深まるという感じです。
もう一つ、勾配法による求め方もあるので、次回やってみようと思います。
以前、A*経路探索アルゴリズムも試してみましたが、このあたりのテクニック/アルゴリズムは、いろいろな場面で使えるので、知っていれば便利かと思って試している最中です。

続き:
線形回帰のプログラミング(その2):勾配降下法

人気の投稿