GCPの無料クラウドVMが性能アップするらしい(F1-Micro → E2-Micro)

突然GCPからメールが届いた

 突然GCP(Google Cloud Platform)からメールが届きました。Googleからなので「またセキュリティ警告かよ」とびっくりして開いたところ、なんと「無料枠のVM(仮想サーバー)が2021年8月1日からグレードアップするからお引越ししてね」という嬉しい内容。

 GoogleにはColab Proで月1,072円課金していますが、正直GCPには課金する魅力を感じていませんでした。今回無償のままグレードアップということで、新VMのインスタンス仕様を調べてみました。

新無料VM『E2-Micro』はメモリ1GBで「まあまあ」

 GCPの料金ページを見ると、

  • 2 つの vCPU の 12.5%
  • メモリ1GB
  • ディスクの記載なし

というわけで、メモリが1GBでOCIに並んだほかはイマイチよく分かりません。vCPUに関しては、おそらく「ご近所が空いている時は2vCPU使ってくれるが、使いすぎたり混んでいる時にはリソースを減らされる」ということだろうと思います。常時フル稼働する用途でなければ、実質的には2vCPUと考えて良さそうです。

ディスクは別枠で最大30GBのストレージをアタッチするらしい

 ディスクに関する記載がなく相変わらず初心者に不親切だなと困っていたところ、Qiitaで「標準永続ディスク ストレージは30 GB まで無料枠内」との記載をみつけました。

 どうやら、何も考えずに無料枠でVMを立ち上げると10GBのSSDが30GBの枠から割り当てられ、明示的に割り当てを30GBに変更することで30GBがフルで割り当てられるようです。「VMとは別枠だからVM側のスペックには記載がない」ということなのでしょう。

持っておいて損はなさげ

 これまでのGCPの無料枠は「お情け」「お試し」というイメージがありましたが、OCIに近いスペックになったことで「真面目に使ってみてもいいかな」という印象に変わりました。特にAWS LightSailの最安プランよりはハイスペックなので、なんとなくLightSailを使っている人は引っ越した方がシアワセになれそうです。

 おそらく、VMとストレージを別枠で確保したクラウド構造になっていることで、E2-Microへの引越しもウィザード的に簡単に出来るはずです(ですよねGoogle先生💦)。

【追記】E2-Microに移行しました

 Google先生から告知があった新無料VM開始日の8/1から、時差を考慮して1日遅れの8/2にE2-Microへ移行しました。

 基本的に作業はマウスポチポチだけですが、さすがにVMをいったん止めないとインスタンスのグレード変更は出来ませんでした。インスタンスの停止後『編集』をクリックし、『マシンの構成』から『汎用』『E2シリーズ』『マシンタイプ:e2-micro(2 vCPU、1GBメモリ)』を選び、保存。インスタンスを再起動します。

インスタンスの停止後『編集』をクリックし、『マシンの構成』から『汎用』『E2シリーズ』『マシンタイプ:e2-micro(2 vCPU、1GBメモリ)』を選び、保存。インスタンスを再起動

無事移行。ただし無料かどうかは次の請求まで不明……

 インスタンスの変更後、 e2-microのメモリが1GBになっていることを無事確認しました。apacheとPostgreSQLが動いている状態で600MB以上メモリが余っているのは嬉しいですね。

 しかし、GCPはOCIなどと違って管理画面に『無償です』といった表示は特に出ないので、次回の請求まで無料枠が適用されているかどうかは分かりません。ドキドキですね()

Google Colaboratory(Colab Pro)でkaggleデータをダウンロードする方法[備忘録]

 技術的な要素は無いのですが、忘れやすいのでコピペ出来るように記事を残しておきます。

kaggle.jsonをGoogleドライブに保存しておく

 kaggleのAccount画面でCreate New API Tokenボタンを押してkaggle.jsonをダウンロードし、Googleドライブに保存する(私の場合は’Colab Notebooks’直下)。

Colabの規定ディレクトリにkaggle.jsonをコピー

 Colabのノートブック画面でGoogleドライブに接続。

from google.colab import drive
drive.mount('/content/drive')

 ターミナルでkaggle.jsonを所定の位置に配置。ColabのターミナルではCtrl+C、Ctrl+Vでコピペ出来ないので、それぞれCtrl+InsertShift+Insertのショートカットで代用する(メニューバーの『編集』でもコピペ出来ない……)。

/content# mkdir /root/.kaggle/
/content# cp '/content/drive/MyDrive/Colab Notebooks/kaggle.json' /root/.kaggle/

kaggleコマンドでデータダウンロード

 Kaggleのコマンド自体はkaggleのサイトに表示されるので、コンペの利用条件を承諾してからコマンドをコピペするだけです。

/content# kaggle competitions download -c house-prices-advanced-regression-techniques
Warning: Looks like you're using an outdated API Version, please consider updating (server 1.5.12 / client 1.5.4)
Downloading train.csv to /content
  0%|                                                                                           | 0.00/450k [00:00<?, ?B/s]
100%|███████████████████████████████████████████████████████████████████████████████████| 450k/450k [00:00<00:00, 61.1MB/s]
Downloading sample_submission.csv to /content
  0%|                                                                                          | 0.00/31.2k [00:00<?, ?B/s]
100%|█████████████████████████████████████████████████████████████████████████████████| 31.2k/31.2k [00:00<00:00, 33.8MB/s]
Downloading test.csv to /content
  0%|                                                                                           | 0.00/441k [00:00<?, ?B/s]
100%|███████████████████████████████████████████████████████████████████████████████████| 441k/441k [00:00<00:00, 60.6MB/s]
Downloading data_description.txt to /content
  0%|                                                                                          | 0.00/13.1k [00:00<?, ?B/s]
100%|█████████████████████████████████████████████████████████████████████████████████| 13.1k/13.1k [00:00<00:00, 12.4MB/s]

Colabの操作性は初心者に優しくない

 Colabのインスタンスを立ち上げるたびに各種操作が必要なのが果てしなくだるいですね……。GoogleのColabチームは操作性の向上に消極的なようで、細かいところでストレスが蓄積します。GBレベルのデータダウンロードが厄介なのも大きな弱点です。

 AutoMLがオープンソースでも出てきており、細かいチューニングが不要な用途ではnotebookの体裁すら不要なノーコードの時代になってきています。本来はGUIでボタンぽちーで分析完了出来てしかるべきです。ちなみにお高いDataRobotや無料でもそこそこ使えるAutoAI with IBM Watson Studioでは既にGUIでAutoMLが可能です

伸びしろがある若い方なら思い切ってワークステーションを買ってみては?

 ワークステーションに50万円払える方は、買ってしまってローカルのJupyter Notebookで分析した方がシアワセになれるかも知れません。もちろんLinuxの知識が多少はあることが前提ですが。

 私が大学時代に貯金をはたいて購入したDECのパソコンは50万円しましたから、伸びしろがある方なら無駄な投資にはならないと思います。

Googleドライブの鬼仕様な『フォルダダウンロード』を回避する裏技(Piping Server)

 最近、Google Colab Pro(月1,072円)を契約したので、『NVIDIA V100』という高性能GPUで機械学習ごっこ(GPT-2,BERT等)をして遊んでいます。

 ところが、機械学習は10GB単位で鬼のようにデータを吐き出すので、Googleドライブが100GB有料契約(月250円)でもすぐ満杯になってしまいます。

 学習したモデルを即消しすれば良いのですが、様々なデータを食わせてAIの挙動を比べるような楽しいことが出来なくなってしまいます。

 そこで考えるのが学習データのバックアップ=Googleドライブからのダウンロードです。しかし、Googleドライブがまさかの変な挙動を示しましたので、注意喚起しつつ対処方法を記録しておきます。

圧縮すらされず変なファイルが落ちてくる

 Googleではフォルダをダウンロードしようとすると、一つあるいは複数のzipファイルに圧縮して送ってきます。ところが、2.5GBあるような大きなファイルは、なぜか圧縮せずzipとは別にボコボコ送りつけてくるのです😭

Googleドライブは、圧縮しきれなかったファイルだけ非圧縮で送ってくる。最悪だ

 上図のケースでは、各チェックポイントのフォルダごとに複数個作成されるoptimizer.ptというファイルが非圧縮のままボコボコ落ちて来た例です。ファイル名が重複するので『optimizer-002.pt』『optimizer-005.pt』など謎なファイル名になっています。さすがにこれは私も

「どのoptimizer.ptだよ!!」

キレ気味困惑してしまいます。課金してもデレないGoogleドライブの仕様を何とかして回避しなければなりません。

こうなったら自力で圧縮だ

 Googleドライブの圧縮機能がおかしいなら、自力で圧縮するまでです。Colab ProにはUbuntu Linuxのシェルがついてくるので、notebookにシェルコマンドを記述しなくても普通にシェル芸が使えます。そこで、まずはtar.gzでフォルダごと圧縮します。

シェル間ファイル転送の裏技『Piping Server』

 24時間で落ちるシンデレラ型インスタンス()であるColab Proで、ファイル転送だけのためにサーバーを立てたりトンネリングの設定をするのは面倒くさい。そこで思いついた対策がRyo Otaさんの『Piping Server』です。

 Piping Serverは、遠隔地のシェルのWebブラウザ(curl等)を仲介してWebブラウザ同士で直接テキストやファイルを送受信するものです。追加アプリのインストールが全く要らない、すごい……。

【送信側】 『Piping Server』は、任意のWebブラウザ間で直接ファイルを送受信できるサービス
【受信側】 『Piping Server』は、任意のWebブラウザ間で直接ファイルを送受信できるサービス

あとは、回線品質の安定を祈るのみです……(現時点でまだダウンロード中です💦)

ダウンロード中にColabのセッション切れを防ぐ

  2時間ほどダウンロードしたところで、切断されてしまいました。シェルコマンドが動いていてもColabセンセイは容赦なく未使用とみなしてセッションを切ってしまうようです。

 これはColabでは有名な問題で、既に他の方が解決策を見つけられています:

Google Colab セッション切れを防止する

【追記】Colab Serverとの通信速度が上がらない……

 その後、梅雨の合間を縫って図書館に行き、Piping ServerでColabからローカルへのダウンロードを試みました。しかし、通信速度が低く、1GB/時くらいしか出ません。図書館のネットは1時間に一回くらい切断される仕様なので、もはやファイルを分割するしかありません。

/content/drive/MyDrive/work# ls -al
total 8449838
drwx------ 2 root root       4096 Jun 19 04:41 output
drwx------ 2 root root       4096 Jun 19 04:32 output-3epochs
-rw------- 1 root root 8631501037 Jun 26 23:59 output-3epochs.tar.gz
drwx------ 2 root root       4096 Jun 18 15:37 runs
-rw------- 1 root root   21116052 Jun 18 15:34 train.txt
drwx------ 2 root root       4096 Jun 18 15:01 transformers
/content/drive/MyDrive/work# split -b 1000m -a 2 output-3epochs.tar.gz output-3epochs_p_
/content/drive/MyDrive/work# mkdir split
/content/drive/MyDrive/work# mv output-3epochs_p* split/
/content/drive/MyDrive/work# cd split
/content/drive/MyDrive/work/split# ls -al
total 8429201
-rw------- 1 root root 1048576000 Jun 29 09:08 output-3epochs_p_aa
-rw------- 1 root root 1048576000 Jun 29 09:08 output-3epochs_p_ab
-rw------- 1 root root 1048576000 Jun 29 09:08 output-3epochs_p_ac
-rw------- 1 root root 1048576000 Jun 29 09:09 output-3epochs_p_ad
-rw------- 1 root root 1048576000 Jun 29 09:09 output-3epochs_p_ae
-rw------- 1 root root 1048576000 Jun 29 09:09 output-3epochs_p_af
-rw------- 1 root root 1048576000 Jun 29 09:10 output-3epochs_p_ag
-rw------- 1 root root 1048576000 Jun 29 09:10 output-3epochs_p_ah
-rw------- 1 root root  242893037 Jun 29 09:10 output-3epochs_p_ai
/content/drive/MyDrive/work/split# cat output-3epochs_p_aa | curl -T - https://ppng.io/epochs
[ERROR] Connection on '/epochs' has been established already.
/content/drive/MyDrive/work/split# cat output-3epochs_p_aa | curl -T - https://ppng.io/epochs2
[INFO] Waiting for 1 receiver(s)...
[INFO] A receiver was connected.
[INFO] Start sending to 1 receiver(s)!
% curl https://ppng.io/epochs2 > output-3epochs_p_aa.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_ab.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_ac.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_ad.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_ae.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_af.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_ag.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_ah.tar.gz
% curl https://ppng.io/epochs2 > output-3epochs_p_ai.tar.gz
% cat $ output-3epochs_p_* > output-3epochs.tar.gz
% tar -zxvf output-3epochs.tar.gz

 ただのデータバックアップなのに、気が遠くなる作業です。お金持ちの方は観念してGoogleドライブに多額の納金をするのが現実的かと思います……。

 Colabはお得で面白いサービスですが、なかなか癖も強いので付き合うのは大変そうです……。

【追記】分割もダメでした……

 図書館で数日に分けて分割ダウンロードをして、ローカルでtar.gzの解凍を試みたところ

(base) masaru@MacBook-Pro-15 output-3epochs % tar -xvf output-3epochs_p_aa.tar.gz 
x output-3epochs/
x output-3epochs/checkpoint-5000/
x output-3epochs/checkpoint-5000/config.json
x output-3epochs/checkpoint-5000/pytorch_model.bin: truncated gzip input
tar: Error exit delayed from previous errors.

結局エラーが出て解凍出来ませんでした……。回線品質が劣悪でtarやPiping Serverにエラー補正がないため、ダウンロード途中でデータが壊れてしまったものと思われます。

 そんなわけで、「高速回線がないと使いこなせない」というのが、現時点での私のGoogle Colab Proへの見解です。

【追記】3分割で再試行し、ようやくダウンロード成功

 緊急事態宣言が出て図書館の人出が若干減ったので、3分割で再試行しました。

(base) masaru@MacBook-Pro-15 output-3epochs % cat output-3epochs_p_* > output-3epochs.tar.gz 
(base) masaru@MacBook-Pro-15 output-3epochs % ls -al
total 33769200
drwxr-xr-x  6 masaru  staff         192  7 29 18:15 .
drwxr-xr-x  4 masaru  staff         128  7 12 19:03 ..
-rw-r--r--  1 masaru  staff  8631501037  7 29 18:16 output-3epochs.tar.gz
-rw-r--r--  1 masaru  staff  3145728000  7 12 19:35 output-3epochs_p_aa.tar.gz
-rw-r--r--  1 masaru  staff  3145728000  7 21 19:47 output-3epochs_p_ab.tar.gz
-rw-r--r--  1 masaru  staff  2340045037  7 29 18:08 output-3epochs_p_ac.tar.gz
(base) masaru@MacBook-Pro-15 output-3epochs % tar -xvf output-3epochs.tar.gz 
x output-3epochs/
x output-3epochs/checkpoint-5000/
x output-3epochs/checkpoint-5000/config.json
x output-3epochs/checkpoint-5000/pytorch_model.bin
x output-3epochs/checkpoint-5000/tokenizer_config.json
x output-3epochs/checkpoint-5000/special_tokens_map.json
x output-3epochs/checkpoint-5000/spiece.model
x output-3epochs/checkpoint-5000/training_args.bin
x output-3epochs/checkpoint-5000/optimizer.pt
x output-3epochs/checkpoint-5000/scheduler.pt
x output-3epochs/checkpoint-5000/trainer_state.json
x output-3epochs/checkpoint-10000/
x output-3epochs/checkpoint-10000/config.json
x output-3epochs/checkpoint-10000/pytorch_model.bin
x output-3epochs/checkpoint-10000/tokenizer_config.json
x output-3epochs/checkpoint-10000/special_tokens_map.json
x output-3epochs/checkpoint-10000/spiece.model
x output-3epochs/checkpoint-10000/training_args.bin
x output-3epochs/checkpoint-10000/optimizer.pt
x output-3epochs/checkpoint-10000/scheduler.pt
x output-3epochs/checkpoint-10000/trainer_state.json
x output-3epochs/config.json
x output-3epochs/pytorch_model.bin
x output-3epochs/tokenizer_config.json
x output-3epochs/special_tokens_map.json
x output-3epochs/spiece.model
x output-3epochs/training_args.bin
x output-3epochs/train_results.json
x output-3epochs/trainer_state.json
x output-3epochs/eval_results.json
x output-3epochs/all_results.json

 ようやく無事、解凍までたどりつきました……。

Oracle Cloudの無料枠が太っ腹(ただし初心者向きではない)

AWS以外のクラウドには仮想マシンの無料枠がある

 AWSで構築したcan.ne.jpですが、維持費に毎月数ドルかかります。「AWSのメールマガジンで毎月バウチャーをもらえばホニャララ」という話もあるのですが、AWSでWebサイトを作ると初年無料を除けば基本的に有料です(2021年4月現在)。

 一方で、AWSに対して出遅れ感があるGCP(Google Compute Engine)やOCI(Oracle Cloud Infrastructure)は永年無料でWebサイトを構築出来る仮想マシン(Virtural Machine, VM)を立てられます。

 クラウドに慣れる目的もあり、GCPとOCIの双方で仮想マシンを立ててみましたが、特にオラクルのOCIが太っ腹だったのでご紹介します。

無料枠なのにAWSのLightSailよりハイスペック

 OCIの無料枠『Always Freeリソース』にはデータベースやストレージもありますが、好きなデータベースをインストールして使えるのはAlways Freeコンピュート仮想マシン(VM)インスタンスです。スペックは

  • シェイプ: VM.Standard.E2.1.Micro
  • プロセッサ: 追加のCPUリソースを使用する機能を持つ1/8 OCPU
  • メモリー: 1 GB
  • ネットワーキング: 1つのパブリックIPアドレスと最大480 Mbpsネットワーク帯域幅を持つ1つのVNICが含まれます
  • オペレーティング・システム: 次のいずれかのAlways Free対応オペレーティング・システムを選択できます:
    • Oracle Linux (Oracle Autonomous Linuxを含む)
    • Canonical Ubuntu Linux
    • CentOS Linux

1/8 OCPUってなんぞや?

 「1/8 OCPUってなんぞや?」と調べてみたところ、AMD EPYC 7551 32-Core ProcessorというCPUの1コアが割り当てられていました。最近のCPUは6コア12スレッドくらいあるので、その1コアぶんくらいでしょう。

[opc@mysql ~]$ sudo cat /proc/cpuinfo
processor	: 0
vendor_id	: AuthenticAMD
cpu family	: 23
model		: 1
model name	: AMD EPYC 7551 32-Core Processor
stepping	: 2
microcode	: 0x1000065
cpu MHz		: 1996.249
cache size	: 512 KB
physical id	: 0
siblings	: 2
core id		: 0
cpu cores	: 1
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core ssbd ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 nt_good virt_ssbd arat npt nrip_save
bugs		: fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass
bogomips	: 3992.49
TLB size	: 1024 4K pages
clflush size	: 64
cache_alignment	: 64
address sizes	: 40 bits physical, 48 bits virtual
power management:

processor	: 1
vendor_id	: AuthenticAMD
cpu family	: 23
model		: 1
model name	: AMD EPYC 7551 32-Core Processor
stepping	: 2
microcode	: 0x1000065
cpu MHz		: 1996.249
cache size	: 512 KB
physical id	: 0
siblings	: 2
core id		: 0
cpu cores	: 1
apicid		: 1
initial apicid	: 1
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core ssbd ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 nt_good virt_ssbd arat npt nrip_save
bugs		: fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass
bogomips	: 3992.49
TLB size	: 1024 4K pages
clflush size	: 64
cache_alignment	: 64
address sizes	: 40 bits physical, 48 bits virtual

メモリー1GBは余裕がある

 can.ne.jpが動いているAWS LightSailは最安プランではメモリが512MBしかありません。

LightSailの最安プランはメモリが512MBしかない

 OCIの仮想マシンはメモリが2倍の1GBあるので、アクセス負荷への耐性がLightSailの最安プランよりずっと高いと思われます。今から自分がWordPressのブログサイトを作るなら、少し面倒でもOCIで自分で構築すると思います。

ストレージは100GBまでいけそう

 画像をたくさん置くブログでは気になるストレージ容量ですが、「コンピュート・インスタンスをプロビジョニングする場合、インスタンスはストレージ用に50 GBのブート・ボリュームを自動的に受け取ります」との記述があり基本50GBです。

 さらに「ブロック・ボリュームを作成してアタッチすると、コンピュート・インスタンスのストレージ容量を拡張できます」「すべてのテナンシは、合計100 GBのAlways Freeブロック・ボリューム・ストレージと、5つのボリューム・バックアップを受け取ります」とあるので、ブロックボリュームをアタッチすることで100GBまで拡張出来ると思われます。

 上のLightSailプランの5倍ですね……。

やっちまった…… Oracle Linuxってなに??

 深く考えずにポチポチして仮想マシンを作ったところ、Oracle Linux 7.9という独自Linuxが入ってしまいました。Red Hat Enterprise Linuxのクローンなのでコマンド周りはCentOSに近いのですが、正直

「特に理由が無いのに、よく知らないOSは使いたくない。面倒くさい」

 というのが本音です。UbuntuやCentOSも選べるらしいので、これからOCIを始める方はOS選びに気をつけて下さい。

セキュリティ周りが面倒くさい(間違ってはいないけど)

 OCIでインスタンスを作ると、他社とは異なりデフォルトでファイアウォールが有効になっています。ファイアウォールを設定してポート開放しないとWebサイトすら公開出来ないので、初心者向きではありません。

 とは言え、セキュリティの問題はサイトを公開する以上は避けて通れないので、敢えて苦しんで設定してみるのも良いかと思います。

 また、AWSやGCPには標準で備わっている『Webブラウザ版のSSHクライアント』が無い(ような)ので、RLoginなどのSSHクライアントをインストールするかシェル版のsshを長いコマンドを打って起動する必要があります。こういった「とっつきやすさ」では、OCIはまだAWSやGCPより一歩遅れているように思います。

 オラクルのビジネスモデルを考えると、そもそも初心者やライトユーザーは見込み顧客として想定していないと思いますが……💦

Jupyter NotebookのセルをWordPressに貼り付ける

手作業でJupyter NotebookをWordPressに転記するのはツライ……

 ということでコピペする方法を探してみたところ、nbconvertを使う方法が良さそうです。

$ jupyter nbconvert --to html --template basic gstore-cust-revenue-prediction.ipynb

 生成されたHTMLから該当セルをWebブラウザーのインスペクター(F12キーを押下)でコピーし、WordPressのカスタムHTMLブロックに貼り込みます。

<div class="input">
<div class="prompt input_prompt">In [7]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span><span class="o">,</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span><span class="o">,</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span><span class="o">,</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="nn">sns</span>
<span class="kn">import</span> <span class="nn">json</span><span class="o">,</span> <span class="nn">re</span><span class="o">,</span> <span class="nn">gc</span>                              <span class="c1">#garbage collector</span>
<span class="kn">from</span> <span class="nn">sklearn.preprocessing</span> <span class="kn">import</span> <span class="n">LabelEncoder</span>
<span class="kn">from</span> <span class="nn">ast</span> <span class="kn">import</span> <span class="n">literal_eval</span>
<span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">KFold</span>
<span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">mean_squared_error</span>
<span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">GridSearchCV</span> <span class="c1">#Experimented hyperparams a bit with this</span>

<span class="kn">from</span> <span class="nn">catboost</span> <span class="kn">import</span> <span class="n">CatBoostRegressor</span>
<span class="kn">from</span> <span class="nn">xgboost</span> <span class="kn">import</span> <span class="n">XGBRegressor</span>
<span class="kn">import</span> <span class="nn">lightgbm</span> <span class="k">as</span> <span class="nn">lgb</span>

<span class="k">for</span> <span class="n">dirname</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">filenames</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="s1">'/home/masaru/data/kaggle_google_analytics'</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">filenames</span><span class="p">:</span>
        <span class="nb">print</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dirname</span><span class="p">,</span> <span class="n">filename</span><span class="p">))</span>
        <span class="k">pass</span>
<span class="n">gc</span><span class="o">.</span><span class="n">enable</span><span class="p">()</span>
<span class="n">sns</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">style</span><span class="o">=</span><span class="s1">'whitegrid'</span><span class="p">,</span><span class="n">palette</span><span class="o">=</span><span class="s1">'deep'</span><span class="p">,</span><span class="n">font_scale</span><span class="o">=</span><span class="mf">1.1</span><span class="p">,</span><span class="n">rc</span><span class="o">=</span><span class="p">{</span><span class="s1">'figure.figsize'</span><span class="p">:[</span><span class="mi">8</span><span class="p">,</span><span class="mi">6</span><span class="p">]})</span>
<span class="n">pd</span><span class="o">.</span><span class="n">set_option</span><span class="p">(</span><span class="s1">'float_format'</span><span class="p">,</span> <span class="s1">'</span><span class="si">{:f}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">)</span>     <span class="c1">#to display full numbers in dataframe and not just exponentiated form </span>
</pre></div>

    </div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

    <div class="prompt"></div>


<div class="output_subarea output_stream output_stdout output_text">
<pre>/home/masaru/data/kaggle_google_analytics/test_v2.csv
/home/masaru/data/kaggle_google_analytics/submission.csv
/home/masaru/data/kaggle_google_analytics/deep-learning-keras-ga-revenue-prediction.ipynb
/home/masaru/data/kaggle_google_analytics/gstore-cust-revenue-prediction.ipynb
/home/masaru/data/kaggle_google_analytics/ga-customer-revenue-prediction.zip
/home/masaru/data/kaggle_google_analytics/test.csv
/home/masaru/data/kaggle_google_analytics/sample_submission_v2.csv
/home/masaru/data/kaggle_google_analytics/GoogleAnalytics_Customer_Revenue_EDA_and_Prediction.ipynb
/home/masaru/data/kaggle_google_analytics/sample_submission.csv
/home/masaru/data/kaggle_google_analytics/train_v2.csv
/home/masaru/data/kaggle_google_analytics/train.csv
/home/masaru/data/kaggle_google_analytics/.ipynb_checkpoints/gstore-cust-revenue-prediction-checkpoint.ipynb
/home/masaru/data/kaggle_google_analytics/.ipynb_checkpoints/GoogleAnalytics_Customer_Revenue_EDA_and_Prediction-checkpoint.ipynb
</pre>
</div>
</div>

</div>
</div>

WordPressのテーマにNotebook用のCSSを追加する

 続いて、WordPressの『外観⇒カスタマイズ⇒追加CSS』でJupyter Notebookセル用のCSSを追加します(リンク先ページのソースを参照のこと)。

In [7]:
import numpy as np, pandas as pd, os, matplotlib.pyplot as plt, seaborn as sns
import json, re, gc                              #garbage collector
from sklearn.preprocessing import LabelEncoder
from ast import literal_eval
from sklearn.model_selection import KFold
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import GridSearchCV #Experimented hyperparams a bit with this

from catboost import CatBoostRegressor
from xgboost import XGBRegressor
import lightgbm as lgb

for dirname, _, filenames in os.walk('/home/masaru/data/kaggle_google_analytics'):
    for filename in filenames:
        print(os.path.join(dirname, filename))
        pass
gc.enable()
sns.set(style='whitegrid',palette='deep',font_scale=1.1,rc={'figure.figsize':[8,6]})
pd.set_option('float_format', '{:f}'.format)     #to display full numbers in dataframe and not just exponentiated form 
/home/masaru/data/kaggle_google_analytics/test_v2.csv
/home/masaru/data/kaggle_google_analytics/submission.csv
/home/masaru/data/kaggle_google_analytics/deep-learning-keras-ga-revenue-prediction.ipynb
/home/masaru/data/kaggle_google_analytics/gstore-cust-revenue-prediction.ipynb
/home/masaru/data/kaggle_google_analytics/ga-customer-revenue-prediction.zip
/home/masaru/data/kaggle_google_analytics/test.csv
/home/masaru/data/kaggle_google_analytics/sample_submission_v2.csv
/home/masaru/data/kaggle_google_analytics/GoogleAnalytics_Customer_Revenue_EDA_and_Prediction.ipynb
/home/masaru/data/kaggle_google_analytics/sample_submission.csv
/home/masaru/data/kaggle_google_analytics/train_v2.csv
/home/masaru/data/kaggle_google_analytics/train.csv
/home/masaru/data/kaggle_google_analytics/.ipynb_checkpoints/gstore-cust-revenue-prediction-checkpoint.ipynb
/home/masaru/data/kaggle_google_analytics/.ipynb_checkpoints/GoogleAnalytics_Customer_Revenue_EDA_and_Prediction-checkpoint.ipynb

 無事、表示出来ました。

Ubuntu 21.04でTensorflow-GPUが動いた(ことだけ)

既存のNVIDIA CUDAドライバで大丈夫でした

 まず最初にお断りですが、私はTensorflowの技術的な詳細やディープラーニングの技術については知識が全くありません。単なるインストールログですので、技術的なご期待にはお答え出来ません。予めご了承ください。

 Ubuntu 21.04は正式リリース前のためTensorflow GPUは動かないのではないかと思っていましたが、実際はcuda_11.2.2_460.32.03_linux.runがすんなり動きました。

sudo wget -O /etc/apt/preferences.d/cuda-repository-pin-600 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub
sudo add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /"


wget https://developer.download.nvidia.com/compute/cuda/11.2.2/local_installers/cuda_11.2.2_460.32.03_linux.run
sudo sh cuda_11.2.2_460.32.03_linux.run

nvidia-smi
Thu Apr  8 16:29:59 2021       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 460.67       Driver Version: 460.67       CUDA Version: 11.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  GeForce GTX 1650    Off  | 00000000:01:00.0 Off |                  N/A |
| N/A   49C    P0    15W /  N/A |   3764MiB /  3911MiB |      4%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A      1741      G   /usr/lib/xorg/Xorg                214MiB |
|    0   N/A  N/A      1949      G   /usr/bin/gnome-shell               72MiB |
|    0   N/A  N/A      3535      G   ...AAAAAAAAA= --shared-files       81MiB |
|    0   N/A  N/A      7116      G   ...AAAAAAAAA= --shared-files        5MiB |
|    0   N/A  N/A    312502      C   ...saru/anaconda3/bin/python     3333MiB |
+-----------------------------------------------------------------------------+
sudo apt -y install libcudnn8 libcudnn8-dev
conda install tensorflow-gpu

jupyter-notebook &

 以下はJupyter Notebookでの作業となります。

import tensorflow as tf
print(tf.__version__)
2.4.1
gpu_num = len(tf.config.list_physical_devices('GPU'))
print(gpu_num)
1

 勉強会でみんな大好きiris、titanic、mnistを今さらやっても得られるものは無さそうなので、文系の私でも興味を持てそうなサンプルコードを見つけて実行してみようと思います。

Analyzing Google Analytics data using TensorFlow GPU

Jupyter NotebookからPythonでPostgreSQL 13を操作する

まずは堅実に定番RDBから

 NoSQLブームで勉強会界隈では影が薄れた感があるRDBMSですが、当たり前の存在になっただけで健在です。当サイトが使っているCMS『WordPress』にはMySQLが組み込まれていますし、当サイトを置いているAWSでもPostgreSQLがRedShiftやAuroraなど基幹サービスで使われています

 統計モデリングを知らないのにディープラーニングでイキる人が信用出来ないのと同様、RDBMSを知らないのにNoSQLを語るのもイタい人です。私も昨年はElasticsearchなどのNoSQLやApache Igniteなどの分散データベースにハマっていましたが、自分のイタさに気づいたためPostgreSQLを学び直しています。

 NoSQLや分散データベースを業務で使いこなしている方々の講演は勉強会で聞くことが出来ますが、彼らは「RDBMSを経験した上でNoSQLに進んでいる」のです。未経験者が講演を聞いていきなりNoSQLに行くのは『悪手』です。

初心者がNoSQLや分散RDBでやりたいことはPostgreSQLでも出来ている

 NoSQLが主に扱うJSONはPosgreSQLでも『JSON型』として扱えます。IMDBで話題となったインメモリ処理はPostgreSQLでも駆使されています。分散データベースの特徴であるクエリの並列処理はPostgreSQLでもパラレルクエリとして実装されている上、特別の設定無しで自動的に使ってくれます。

 昨年、実際にApage IgniteでPCサーバ5台のクラスタを構築しましたが、数10GB程度のデータではクエリに要する時間がシングルノードのPostgreSQLの方が速かったです。2.5GbEでもLANの遅延で並列処理のメリットが相殺されてしまいます。この規模のデータでクエリを高速化するなら、32コア64スレッドのパソコンでも買えば良いと思います。

 こういう事実は、基本的すぎて勉強会ではなかなか教えてもらえないですね。エンジニアの方にとっては常識なのでしょうが……💦

PythonでPostgreSQLを扱うパッケージ『psycopg2』

 PythonでPostgreSQLを扱う際は『psycopg2』というパッケージを使うのが一般的なようです。視覚化のためのパッケージ『Plotly』と併せてインストールします。

(base) masaru@ASUS-TUF-Gaming:~$ conda install psycopg2
(base) masaru@ASUS-TUF-Gaming:~$ conda install plotly

Jupyter Notebookでの実装

 必要なパッケージの読み込みなどの初期設定を行います。

# -*- coding: utf-8 -*-
import psycopg2
import pandas as pd
import plotly as py
import plotly.graph_objs as go
from plotly.offline import iplot, init_notebook_mode
init_notebook_mode()

 psychopg2でデータベース接続を定義します。

def connect():
    con = psycopg2.connect("host=" + "localhost" +
                           " port=" + "5432" +
                           " dbname=" + "google_mobility" +
                           " user=" + "masaru" +
                           " password=" + "xxxxxxxxxxxx")
    return con

 続いて、クエリを定義します。

def select_execute(con, sql):
    with con.cursor() as cur:
        cur.execute(sql)
        rows = cur.fetchall()

    return rows

 定義したクエリを実行します。

con = connect()
sql =  "select * from google_mobility where SUB_REGION_1 = 'Tokyo'"
result = select_execute(con, sql)

 クエリの結果をPandasデータフレームに代入します。

df = pd.DataFrame(result)
df.head()

 とりあえず全部カラム名をつけてあげます。

columns = ["id","country_region_code","country_region","sub_region_1","sub_region_2","metro_area","iso_3166_2_code","census_fips_code","date","retail","grocery","parks","transit","workplaces","residental","place_id"]
df.columns = columns
df.head()

 Plotlyで表示するデータを設定します。

trace1 = go.Scatter(
        x = list(df.date),
        y = list(df.retail),
        mode = 'lines+markers',
        name = 'retail',
        marker = dict(
                color = 'blue'
                )
        )

trace2 = go.Scatter(
        x = list(df.date),
        y = list(df.grocery),
        mode = 'lines+markers',
        name = 'grocery',
        marker = dict(
                color = 'orange'
                )
        )

data = [trace1, trace2]

 続いて、Plotlyの特長であるスライダーを設定します。

layout = dict(
    title='Time series with range slider and selectors',
    xaxis=dict(
        rangeselector=dict(
            buttons=list([
                dict(count=1,
                     label='1m',
                     step='month',
                     stepmode='backward'),
                dict(count=6,
                     label='6m',
                     step='month',
                     stepmode='backward'),
                dict(count=1,
                    label='YTD',
                    step='year',
                    stepmode='todate'),
                dict(count=1,
                    label='1y',
                    step='year',
                    stepmode='backward'),
                dict(step='all')
            ])
        ),
        rangeslider=dict(
            visible = True
        ),
        type='date'
    )
)

 グラフを描画します。

fig = dict(data=data, layout=layout)
iplot(fig)

 スライダーを動かせるグラフの出来上がりです。

Kaggleのデータをコンペ以外の目的で利用する

データサイエンティストに敵わないからといって避けて通るのはもったいない

 Kaggleはコンペティションで有名なため「データサイエンティスト以外はお断り」というイメージがあります。しかし、優秀な方々に及ばないことが分かっていてもKaggleを避けて通るのはもったいないと思います。

 BIツールの学習など、実務寄りのデータがほしい機会は多くあります。Kaggleにどのようなデータがあるか知っていれば、目的に近いデータを入手出来ます。特にマーケティング分野のデータは企業秘密の塊であり一般公開されることが少ないため、Kaggleのデータはとても貴重なものです。

 本日は、昨年Twitterでも触れていた「Google Analytics Customer Revenue Prediction – Predict how much GStore customers will spend」をご紹介します。

実在するEコマースサイトのアクセスログ

 このコンペはRStudio社の主催で、GoogleのEコマースサイト『GStore』のセッション単位のアクセスログが約33GB、提供されています。

 CSVのカラムにJSON風のデータが詰め込まれていて処理が手強いですが、BIツールの基本である日次統計にもってこいです。参考書籍などで数10GBのデータを扱っている例は見たことがありませんが、これくらいのサイズがなければExcelで十分であり、データベースやBIツール、データ分析基盤などのスケーラビリティを試すなら最低でもGB単位のデータが必要です。

 昨年はこのCSVデータを自力での展開を試みましたが、データ構造が複雑なため簡単な置換処理ではテーブル構造に出来ませんでした。今年は先達の方のnotebookなどを参考にして、まずはPostgreSQLへのデータ格納までたどり着きたいと考えています。他の方から学べるのもkaggleの良いところですね。

(base) masaru@ASUS-TUF-Gaming:~$ conda install --channel https://conda.anaconda.org/conda-forge kaggle
(base) masaru@ASUS-TUF-Gaming:~$ kaggle competitions download -c ga-customer-revenue-prediction