G検定を受験しました(受験記)
最近Kaggleで基本的なコンペに参加していたのですが、職場で話題になったことをきっかけに、G検定を2021年11月6日に受験し、合格しました。特に会社が後押ししているというわけでもなかったので、独力での取り組みとなりました。
資格試験自体久しぶりで面白かったので、自分の取り組みをメモに書き残しておきます。
前提
他の方が受験対策に読むかもしれないので、試験勉強を始める前の水準を書いておきます。
長いことプログラミングは趣味で行っており、プログラム自体は苦にならないです。
しかしずっとアマチュアプログラマーであり、職業プログラマーとしてのキャリアはありません。
仕事では身の回りの業務を便利にするツールを作る程度です。
機械学習を触り始めたのは比較的最近のことです。ここ数ヶ月、KaggleでCoursesをいくつか受講し、Tabular Playground SeriesのOct 2021とSep 2021に参加した程度の駆け出しレベルです。
Oct 2021ではひたすら他のかたのShareした情報をみて同じことをやってみて、少し自分なりの変更を加える、という手習いを繰り返しました。Sep 2021では手元のPCにCUDAをセットアップして(Windows 10)動かすことができました。
英語は、コンピュータ関係の文書を読むのはさほど苦労しません。Kaggleは英語ばっかりですけど、拒絶反応を示さない程度には大丈夫です。それから、大学では数学をやっていました。テンソルと聞いたとき、ああやったなぁそういうの、と思うくらい過去のことです。
事前検討~学習
安易に「G検定 勉強時間」でググると、必要な勉強時間は30時間とでてきますが、これは取り組み前の水準がどの程度であることを前提としているのか全くわからないので参考になりません。とりあえず、公式問題集を買いました。購入履歴を確認すると、9/30のことなので、約5週間前です。
テキスト購入の時点で試験の申込みは済ませてありました。締切がきまらないとやる気がでないので、先に申し込むのはおすすめです。
公式問題集ですが、あとからこれを買うかたには、紙の本をおすすめします。私はKindle版を買いましたが、問題ページと回答/解説のページが離れているので、行ったり来たりしながら読むのは正直苦痛でした。紙版なら楽に読めると思います。これに耐えつつ取り組んだのですが、正直いらない苦労だったと思います。
ひとしきり終わったところで時間があったので、10/23に公式テキストを買いました。こちらもKindle版です。問題集と違って前後する必要はないので、最初から流して読んで、知らないところを中心に読み込みました。Kaggleで実技の基本的なところは抑えていたので、そのあたりは読み飛ばしました…… が、各種のアルゴリズムやモデル名とその特徴など、用語はもう少し細かく覚えるべきだったと思います。
G検定は実技ではなく知識を問う試験なので、これまでの歴史的経緯や用語は非常に沢山でてきます。言葉を多く覚えると合格に近づきます。その意味では、この受験勉強はどんどん脇道にそれてゆくのが面白いです。ENIACについて読んだら、WikiPediaのページをナナメ読みしたりしました。
公式テキストを読んでから問題集に移るやりかたが一般的だと思いますが、私は逆にやりました。取り組み期間が短いと思っていたので、試験に対して実践的なところから入るしかないかと考えたためです。普通は、テキストから入ったほうが良いと思います。
受験
自宅でブラウザ経由での受験です。試験会場に比べて緊張感はありません。事前にコーヒーを用意しておくのは重要です。ややこしい問題文を音読しても誰にも迷惑がかからないのが良いですね。
試験時間に比べて問題数が多いので、悩んでいる時間はありません。わかるところはすぐ次へ、ちょっと考えてわからなかったらあとから振り返るチェックを入れて次へ、と流してゆきます。受験してみて驚いたのですが、時事問題が多く、個人情報漏えいに関する最近の社会の動向だとか、囲碁将棋などでの発展度合いなど、試験勉強とは別にAINOWなどのニュースをチェックしていればわかる問題もかなり多かったです。公式テキストには明らかになかっただろうな、という最近の話題も出題されるのが驚きでした。
先程も書いたように実技ではなく知識を問う問題なので、知らないものは考えてもわかりません。ただ、あとに続く問題に関連する用語がそれとなく含まれていたりするので、正解できているか不安な問題は、あとで確認するチェックを入れておいたほうが効率が良いです。同じ分野の問題を読んだあと戻ってくると、2~3問は拾えるかもしれません。
結果発表と感想
2週間ほどで結果の通知がメールで届きます。通知と併せて、有資格者向けのSlackが紹介されてきます。登録したばかりなので、今後覗いてみようかと思っています。
この試験、ジェネラリストと題されているだけあって、職場で方針を決めたりする立場のかた向けの資格だと思います。人類が、これまで長いこと機械学習の研究に取り組んできて、壁にぶつかるたびに何がブレイクスルーになり、その新しい技術には利点・欠点があり、新たな課題が現れ…… という、この業界全体の流れを把握することができます。
この経緯がわかっていないと、職場で見当違いの方針を採用してしまったりするのだと思います。管理職の方におすすめですね。
全体としては、この試験勉強はやってよかったと思います。Kaggleでマニュアルを読んでも、そのアルゴリズムが実装されている経緯はわかりません。なぜこんなにいろいろな機械学習アルゴリズムがあるのか、どれが先でどれがあとなのか、何が得意で苦手なのか、など全体的に把握するには良いものだと思いました。
トラックボールマウス(ERGO M575)
在宅勤務になってはや一年半。ほとんど会社に出勤しない日が続いているのですが、在宅労働環境も少しずつ充実させています。
最近購入したのが、トラックボールマウス ERGO M575。
一日中マウスを使っているせいか、右の手首から肘にかけてが痛くなってしまい、マウスを持つ手の手首のひねり具合が良くないという話を見つけました。トラックボールは初めてなのですが、これは手首のひねりが少なく、親指がやや天井のほうに向いたポジションでつかむことになります。ついでに、マウス自体を動かさないので肘を置いたままにできるということがあります。
しばらく使ってみて気がついた良いところ悪いところですが……
良いところ
- 手首がらく
- 肘を置いたままにできるので右肩が疲れない
- マウスパッドがいらない
難点
- 細かいポイントがしづらい。最近ウインドウの端を掴むのが難しい。歳か? 親指が不器用なのか?
- 100年ぶりにマウスのボールを掃除した。月に1回ボールの掃除。そんなの忘れられた文化だと思ってた。
- 追加のプログラマブルボタンがほしい。左右クリックとダイヤル以外には、2個ボタンがあるけど、あと2個くらい欲しい。
親指を自在に動かしてポイントするって意外と難しいですね。人差し指と中指で操作するタイプだともう少しやりやすいんでしょうか。ただ、それだとクリックする指はどうしたらいいのかと思いますし。しばらくこのスタイルで過ごそうと思います。
Google日本語入力で無変換キーでIMEをオン/オフする
前置きとしてのエピソード
ありがちな話なのですが、Steamの、とあるKOEIの古いゲーム(信長の野望 革新 PK)を購入したあと、どういうわけかゲームを起動するとキー入力をまったく受け付けず、事実上ゲームがフリーズするという問題に遭遇しました。不良品を買ってしまったのか? Windows 10はサポートしていると書いてあるのに、こんな起動直後に何もしないうちから操作不能になるバグありえる? と困惑したのですが、Steamコミュニティにはこの問題がすでに報告されていました。
いわく、Google日本語入力を使うと普通に遊べる、とのこと。
……なんじゃそりゃ。
でも、実際この対処で遊べました。めでたしめでたし。
こんな経緯で、Google日本語入力を初めて試すことになりました。変換効率いいのかな。しばらく試してみようと思っています。
本題
……ところで、標準的には、日本語IMEは[半角/全角]キーが日本語入力のオン/オフに対応しています。しかし、頻繁にオン/オフする割にはこのキーは遠くにあります。手がホームポジションを離れるので、効率が悪いわけです。そこで普段、あまり使わない[無変換]キーをオン/オフに割り当てることにしています。これ、すべての日本語ユーザー(?)にオススメです。
Google日本語入力でもこれを設定しようと思ったのですが、カスタマイズのしかたが直感的にわかりにくかったのでメモを残しておきます。
以下が標準のキー設定(プロパティ→キー設定の選択→編集)。IMEを有効化/無効化の項目でソートしてあります。
わかりにくい原因は「変換前入力中」「変換中」「文字入力なし」「直接入力」の意味がいまいちイメージしづらいことにあると思います。
結論から言うと、以下の行を追加する必要があります。
- 「直接入力」(=日本語入力モードになっていない)のときに[無変換]キーを押すと「IMEを有効化」する
- 「文字入力なし」(=日本語入力モードになっているが、文字入力していない)のときに[無変換]キーを押すと「IMEを無効化」する
設定後はこうなります。Muhenkanとあるところを追加です。
ステートマシン的な考え方をするとGoogle日本語入力の状態遷移はこんな感じでしょうか。
「直接入力」→(IMEを有効化)→「文字入力なし」→(文字入力)→「変換前入力中」→(変換開始)→「変換中」→(確定)→「文字入力なし」
日本語入力は基本的なインフラなので、細かいこだわりがある人も多いかと思います。こんなの便利だよ、みたいなコメントを頂けると参考になります。
Windows 10でMediaPipeで遊ぶ(VSCodeを添えて)
GitHubに、google/mediapipeというレポジトリがあります。
今回初めて知ったのですが、Google製の物体認識関係のエンジンで、AndroidやiOSを含む、多くのデバイスで共通で動かせるとのこと。以前は物体認識としてYOLOv3で遊んだのですが、こちらは物体認識以外にもPose Estimation(ポーズの推測)ほかいろいろな機能があり、特に実用性の高そうな人の動きを認識させることが可能です。手の動きを認識する機能にちょっと興味がでたので、今回はこれを動かします。
これ自体は「チュートリアル動かしてみた」程度のことなのですが、Visual Studio Codeから動かせるようにするのに少し苦労したので環境構築部分のメモを残しておきます。
Python 3.9環境を作成
Windows環境のPythonでは、普段はAnacondaを使っているのですが、今回はまともにMediaPipeを動かすことができませんでした。試行錯誤の結果Windows StoreにあるPython 3.9で動かしています。多分だけれど、Anacondaにデフォルトで入っているOpenCV2や他の類似のエンジンと、どこかでモジュール名がかぶっているのかもしれません。
ざっくり下のような手順で、まっさらなPython環境を作りました。
C:\Users\windv>cd Python3.9_MediaPipe
C:\Users\windv\Python3.9_MediaPipe>python -m venv mp_env python=3.9
C:\Users\windv\Python3.9_MediaPipe>.\mp_env\Scripts\activate
(mp_env) C:\Users\windv\Python3.9_MediaPipe>python -V
Python 3.9.5
(mp_env) C:\Users\windv\Python3.9_MediaPipe>
(mp_env) C:\Users\windv\Python3.9_MediaPipe>pip install mediapipe
VSCodeから利用
このあと、ソースフォルダを作成してそこをVSCodeで開きます。
そしてPythonのスクリプトをなにか作成して、その状態でターミナルを開き、ターミナルの種類をPowershellに変更、さらにVSCode上でCtrl+Shift+Pで「Python: Select Interpreter」を選びます。
そのあとvenvにあるpython.exeのある場所を指定すればOKでした。
(おまけ)サンプル動きました。
USBカメラ(解像度はそれほど高くない、安いもので十分)、をつなぎ、下のMediaPipe Handsサンプルを動かしました。
import cv2 import mediapipe as mp mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands drawing_styles = mp.solutions.drawing_styles # For webcam input: cap = cv2.VideoCapture(0) with mp_hands.Hands( min_detection_confidence=0.5, min_tracking_confidence=0.5) as hands: while cap.isOpened(): success, image = cap.read() if not success: print("Ignoring empty camera frame.") # If loading a video, use 'break' instead of 'continue'. continue # Flip the image horizontally for a later selfie-view display, and convert # the BGR image to RGB. image = cv2.cvtColor(cv2.flip(image, 1), cv2.COLOR_BGR2RGB) # To improve performance, optionally mark the image as not writeable to # pass by reference. image.flags.writeable = False results = hands.process(image) # Draw the hand annotations on the image. image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) if results.multi_hand_landmarks: for hand_landmarks in results.multi_hand_landmarks: mp_drawing.draw_landmarks( image, hand_landmarks, mp_hands.HAND_CONNECTIONS, drawing_styles.get_default_hand_landmark_style(), drawing_styles.get_default_hand_connection_style()) cv2.imshow('MediaPipe Hands', image) # ESCキーで終了 if cv2.waitKey(5) & 0xFF == 27: break cap.release()
まだ最初の一歩だけなのですが、YouTubeの動画と連携する機能があったりして、なにかおもしろい遊びができるかもしれません。
C言語のポインタの奇妙な表現
某ツイッターに書かれていた記載を見て本当か? と思って実験したので記録してみました。
■ 問題
int a[10];
のような配列を定義したとき、下は全部同じ。
a[1]
*(a+1)
*(1+a)
1[a] ←え?
■ 実験
私としては、C言語ってとても数学的な文法の組み立てなので、言われてみればそうなるなぁと思ったのですが、しかし、数値リテラル(ここでは1)は暗黙のint型なので、a[]がint型の配列ではない場合はほんとに a[1] と 1[a] は同じになるのだろうか、と思ったのです。
ここのところを実験してみました。
環境はWindows 10のWSL2環境のUbuntuです。aptでgccがインストールしてあります。
とりあえず練習です。ポインタが指し示すアドレスを表示するときはprintfに%pで指定します。
windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ cat 001pointer.c #include<stdio.h> int main(){ int a; printf("%p\n", &a); } windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ ./001pointer 0x7ffe6e1564c4 windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$
簡単ですね。ということで次はint型の配列です。
windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ cat 002pointer.c #include <stdio.h> int main(int argc, char* argv){ int a[100]; printf("sizeof a[0]=%d\n", (int)sizeof(a[0])); printf("sizeof 1[a]=%d\n", (int)sizeof(1[a])); printf(" &a[1]=0x%p\n", &(a[1])); printf(" (a+1)=0x%p\n", (a+1)); printf(" (1+a)=0x%p\n", (1+a)); printf("&(1[a])=0x%p\n", &(1[a])); } windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ ./002pointer sizeof a[0]=4 sizeof 1[a]=4 &a[1]=0x0x7ffecaea5624 (a+1)=0x0x7ffecaea5624 (1+a)=0x0x7ffecaea5624 &(1[a])=0x0x7ffecaea5624 windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$
実行するとサラッと結果がでますけど、1[a]のアドレスはやっぱり違和感ありまくりです。
で、私が疑問に思っていたintではない場合どうなるの?ということですが……
windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ cat 003pointer.c #include <stdio.h> int main(int argc, char* argv){ long long a[100]; printf("sizeof a[0]=%d\n", (int)sizeof(a[0])); printf("sizeof 1[a]=%d\n", (int)sizeof(1[a])); printf(" &a[1]=0x%p\n", &(a[1])); printf(" (a+1)=0x%p\n", (a+1)); printf(" (1+a)=0x%p\n", (1+a)); printf("&(1[a])=0x%p\n", &(1[a])); } windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ ./003pointer sizeof a[0]=8 sizeof 1[a]=8 &a[1]=0x0x7ffd1b2cee18 (a+1)=0x0x7ffd1b2cee18 (1+a)=0x0x7ffd1b2cee18 &(1[a])=0x0x7ffd1b2cee18 windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$
う~ん、long long型のように8byteのメモリをとる変数でも結果は同じなんですね。これは私の予想に反する結果でした。sizeof(1[a])の結果がaの型によって変わるというのがどうにも理解できません。これはどう考えたらいいの……?
【雑文】目標の達成とプログラミングは似ている
最近は、小学校でもプログラミング教育をするんだそうですね。
コンピュータをより適切、効果的に活用していくためには、その仕組みを知ることが重要です。コンピュータは人が命令を与えることによって動作します。端的に言えば、この命令が「プログラム」であり、命令を与えることが「プログラミング」です。プログラミングによって、コンピュータに自分が求める動作をさせることができるとともに、コンピュータの仕組みの一端をうかがい知ることができるので、コンピュータが「魔法の箱」ではなくなり、より主体的に活用することにつながります。
私がプログラミングに初めて触れたのは小学校4年生の時で、友達の家にMSXがあったのを触った時でした。BASICが内蔵されていて、ちょっとした命令でピッ!とか音が鳴る(BEEP)ようなものでも、機械が自分の命令で動作したということですごく面白く感じました。BASICの良いところは、命令単体でもちょっとしたことができるので、手探りでまとまった仕事をくみ上げてゆける、というところです。
コンピュータに何か仕事をさせるには、細かく段取りを決めてひとつひとつ記述するプログラミング力が求められます。よくよく考えてみると、これは、自分自身が何かをやりたいときでも、ゴールにたどり着くまでの工程を細かく分けて、ひとつひとつやっていくことと共通点があります。
- やりたいことを思いつく。
- やりたいことを達成するまでを細かいステップに分けて段取りする。
- ステップをひとつひとつ具体的にやってみる。
- たいていどこかでつまづくので、トラブルシューティングする。
- 当初の目的を達成する。
- 少しできると、もっとやりたくなる、こともある。最初に戻る。
どの段階も大事なのですが、二番目の段取りで「どうしたらいいか、わからない」、そして四番目のトラブルシューティングで「どうしたら上手くいくようになるのか、わからない」が、人生の悩みの大半ではないかな、と思います。ぶっちゃけこれ以外は、ネット全盛期ですから、調べればたいてい例がみつかります。
冒頭の手引を見ると、プログラミング教育では二番目の段取り力の養成を重視しているようなのですが、私の肌感覚では、四番目のトラブルシューティングこそがこの先生きのこる重要スキルではないかなと感じます。人生のデバッグ力、大事ですよね。