一色からは「ONEXPLAYER X1 AMD版で楽しむChatGPT×プログラミング」という題でX1を数週間使って気付いた問題と、その解決のために始めたChatGPTを駆使したプログラミングについて、かわさきからは「何をもってPythonicなのか(refrain)」という題でforループとif文を使って書いたコードとリスト内包表記で書いたコードのどちらが「初心者にとって分かりやすいか」「Pythonicなのか」について書きました。
@ITのDeep Insiderフォーラム【AI・データサイエンスの学びをここから】を担当しているDeep Insider編集部の一色とかわさきです。5月初旬に公開した編集後記から3カ月ぶりですね。
編集者が記す「あとがき」である、この編集後記では、執筆/編集時には書けなかった小話や裏話、感想、ぜひ読者にも知ってほしいという話などを書いています。
@ITのDeep Insider編集部の編集長。仕事でのモバイル用には13.3インチのMacBook Airを使っていますが、ビジネスリュックで持ち運ぶサイズです。最近になって、もっと気軽に持ち歩けるよう「普段のお出かけ用ショルダーバッグに入る小型ノートPC(UMPC:ウルトラモバイルPC)が欲しい」と思い始めました。キーボードがまともに使えるサイズとして10〜11インチ程度を検討していたところに、「ノートPC」にも「Windows 11タブレット」にも「ハンドヘルドゲーミングPC」にもなる“3in1 PC”の「ONEXPLAYER X1 AMD版」が販売開始されたので「これだ!」と衝動買いしてしまいました。
自己紹介にも書いた通り、最近、ONEXPLAYER X1 AMD版(国内正規版)を購入しました。このデバイスを持っているだけでワクワクしています。ちなみに、仕事用ではなく、完全に個人の趣味のために使っています。
このデバイスについて語り出したらキリがないのですが、今回は数週間使ってみて感じたことや、このデバイスのために実施したプログラミングやAIに関することについて書こうと思います。
とはいえ、ONEXPLAYER(ワン・エックス・プレイヤー)がどういう製品かを知らない人が多いと思いますので、最初に簡単に紹介しておきます。私も購入するまで知らなかったので。
ONEXPLAYERは、中国(深セン)のOne-Netbook社が設計し製造する製品です。大きめのディスプレイサイズでハンドヘルドゲーミングPCを幾つか展開しており、具体的には主に以下の製品があります。
ONEXPLAYER X1には、2024年5月販売開始のX1 Intel版もありますが、ゲームをするならAMD版の方がよいと言われています。
ハンドヘルドゲーミングPC市場は今、競争が熾烈(しれつ)で、最も有名なSteam Deck(スチーム・デック)を筆頭に、ASUSのROG Ally(アール・オー・ジー・エーライ)、LenovoのLegion Go(レギオン・ゴー)などがあります。ただしこれらは、ノートPCとして使うには画面が小さいし、キーボードが付属しないので私の購入候補には入りませんでした。
最後まで悩んだのが2024年5月販売開始のGPD WIN Max 2 2024という製品です。非常に良さそうなのですが、タッチパッドが上部にあるのが気に入らなかったのと、ゲームがONEXPLAYER X1よりも遊びづらそうに感じました。あとは購入希望時期と製品販売開始のタイミングが一致したという理由で、最終的にONEXPLAYER X1 AMD版(国内正規版)を購入しました(ちなみにクラウドファンディングのIndiegogo版もあります)。
ONEXPLAYER X1 AMD版は「ゲーミングPC」というジャンルの製品だけあって、パソコンとしても高性能です。AMD Ryzen 7 8840Uを搭載しており、8コア16スレッドのCPUと、AMD Radeon 780M(12コア)のグラフィックス(iGPU:内蔵GPU)、AMD Ryzen AI(NPUを含むAIエンジン)も利用可能です。メモリは32GBで、SSDは2TBもあり、さらに高い冷却性能を有しています。これだけのスペックがあれば、ほぼ何でもできると思います。開発のためにVisual Studio(統合開発環境)もインストールしましたが、問題なく使えています。
ONEXPLAYER X1 AMD版は「AI PC」のカテゴリーに入ると思いますが、NPU単体の性能は最大16TOPSしかなく、40TOPS以上のNPUが必要な「Copilot+ PC」にはなれないようです。とはいえ今後、NPU(AIの推論処理)に対応するアプリ(代表例:Windows Studio Effectsなど)が増えていくかどうかは、現時点で未知数だと個人的には感じています。
AMD Radeonグラフィックス(内蔵GPU)を使用した機械学習(ROCmソフトウェア+PyTorch/TensorFlow)もできそうな気がしますが、手元にGPU搭載のWindows PCとLinux(Ubuntu) PCがあるので、機械学習や生成AIのためにONEXPLAYER X1を使うことはないだろうと思います。
一色さんがゲーミングノートPCを買うほどゲーム好きだとは思ってもいませんでした(かわさき)。
むしろX1 AMD版を買ったから、ゲームのSAND LAND(サンドランド)を購入したぐらいなので、そこまでゲーマーではないですね……。X1は、メインは「ノートPC」として使い、+αが「ゲーム」ぐらいで使うのに適したデバイスだと思います。
こんなONEXPLAYER X1 AMD版ですが、ノートPCとして使うのであればほとんど問題はありません。しかし、欠点もあります。
例えば、Web会議でGoogle Meetを使うと、自分の映像が上下逆さまになる問題があります。コンバーチブル型でディスプレイが回転する場合によくある問題のようで、Windowsの設定で[画面の向き]が「横(反対向き)」になっているのが影響していると思います。OBS Studioの仮想カメラを使って上下を反転させれば問題を解消できます。もしくはZoomを使うか。
また、タッチパッドに関連する問題も大きいです。まず、Windowsで設定できるタッチパッドの詳細な設定機能が用意されておらず、これは恐らくドライバの実装のせいではないかと考えています。One-Netbook社はソフトウェア部分の開発が十分でない気がします(ちなみに公式Discordコミュニティーにさまざまな報告があります)。
そのため、その弱い部分を筆者の自力で補おうと、Visual Studioをインストールして自分のために開発を行っている状況です。これはこれで、このデバイスがかわいく感じる理由ではあるのですが。
で、その問題とは、キーボードを折りたたんで「ふた」を閉じた状態でも、机が少し揺れただけでタッチパッドが反応し、「マウスが動いた」と判定されて自動的にスリープ(モダンスタンバイ)から復帰してしまうことです。
これを避けるために、ふたを閉じるとタッチパッドを無効化し、ふたを開けると有効化するWindowsアプリ「WinSleepWell」をC#で開発しました(オープンソース:GitHub ― WinSleepWell)。このアプリは、WPF(Windows Presentation Foundation)のタスクバー常駐型アプリとして.NET 8で作成しました。
この時、ChatGPTを使って質問しながら90%以上を作ってもらうことができました。もちろん、自分の知識やスキルも発揮して開発方法や使用するAPIを指示しましたが、生成AIは確かに開発に役立ちます。しかし、コードが長くなると1回の生成が長大になるので、ある程度の段階になるとGitHub CopilotやCursor(Visual Studio CodeをフォークしたAI支援特化のコードエディタ)が必要になると感じました。
今日、記事制作用に自作した別のアプリのプログラミングでCursorを使ってみたのですが、長年、悩んでいた不具合の問題を解決できました(たぶん)。本当に良いツールですね。
そういえば、かわさきさんも「GitHub Copilotを試している」と言っていましたね。実用性はどうでしょうか?
ぼくはVisual Studio Code+GitHub Copilotな環境で『解決!Python』のサンプルコードを書いているのですが、何かのモジュールをインポートすると、その時点で意図を察知して、コード生成が動き始める感じですね。サンプルコードを自分で書くことに意味があると思っているので「ちょっとちょっと!」と思って、生成されるコードを([Tab]キーで確定するのではなく)自分のコードで上書きしています。結果、同じコードを入力することもありますが(笑)。
WinSleepWellはしばらく安定動作していたので、これで完成かと考えていましたが、他にも伏兵がいました。Windowsの自動メンテナンス機能です。
この機能がスリープを勝手に解除します。映画や動画、本を見ているときに電源やディスプレイが切れるのが嫌なので、これらの自動切断は「なし」に設定しています。よって、自動メンテナンスの後に自動的にはスリープしません。そのため、「気付いたら、Windowsが起動したままになってしまう」という問題が新たに浮上してきました。
ちなみに、自動メンテナンス機能をオフにすると、Windowsの再起動時に時間がかかるようになるので、オフにもできません。よって今度は、「自動メンテナンスが終わって、しかもふたを閉じた状態なら自動的にスリープする」という機能を、WinSleepWellに加えようとしています。
自動メンテナンスの稼働状況を把握するプログラムの作り方は、Google検索では見つけられませんでした。もうGoogle検索では欲しい情報が見つからない時代かもしれません。昔はそういった情報も存在したかもしれませんが、2年以上前のコンテンツの検索順位を下げるような「Google検索アルゴリズムの方針」(※筆者の体感に基づく想定)の影響で、次々と消されていってしまった気がします。本当に困りものです。
この機能についても、ChatGPTに自分の知識とスキルを組み合わせることで実現できました。作業時間が取れず、WinSleepWellにはまだ実装できていませんが。……という感じで、ONEXPLAYER X1オタクな週末を最近は過ごしています。
まじめな仕事の話もしておくと、最近は編集を担当している羽山氏の『やさしい確率分布』がページ参照数で絶好調です。多くの人に読んでいただけてうれしいです。この場を借りてお礼を申し上げます。ありがとうございます。
大学生時代にIT系出版社でアルバイトを始めて、そのまま就職という典型的なコースをたどったダメ人間。退職しても何か他のことをできるでもなくそのままフリーランスの編集者にジョブチェンジ。そしてDeep Insider編集部に拾ってもらう。お酒とおつまみが大好き。最近はすっかり「ダイエットおじさん」に。
実はもう鳥貴族は食べ飽きてしまいました。だって、たんぱく質を摂取する目的で鳥貴族さんにいくと、結局、ささみとレバーと後は串を何種類かしか頼めないんですもん(カロリーが高そうな唐揚げとかは頼まないようにしているので、選択の幅が狭まっちゃうんですよね)。その一方で、このところのあまりの暑さに自炊する気が出てこないので、夕飯は外食頼みになっています(昨日も食べ飽きたはずの鳥貴族さんに行ってしまいました)。その結果、一時は60キロを割り込んだ体重は減るどころか若干増え気味です(ダメだー)。
ここ最近、ChatGPTを使った「Pythonコード10本ノック」みたいなことをしているんですよ。そこである日、こんな問題が出されました。
問題のコードはもちろんリスト内包表記を使えばシンプルに記述できます。Pythonプログラマーなら、for文とappendメソッドが出てきたら、すぐに「これはリスト内包表記」と反射神経的に対応するでしょう。
でも、ふと思ったのです。初心者にとって「明確なコード」はどっちなんだろうと。2つの関数を比べてみましょう。
def extract_even_numbers_0(numbers):
result = []
for number in numbers:
if number % 2 == 0:
result.append(number)
return result
def extract_even_numbers_1(numbers):
return [number for number in numbers if number % 2 == 0]
「for文の中でリストの要素を取り出して、それが偶数かどうかを判定して、そうであれば結果を格納するリストにそれを追加する」という処理が明確に表現されている(そして、初心者が理解しやすい)コードはextract_even_number_0関数(Pythonicじゃない方)な気がしませんか? でも、Pythonicなコードはextract_even_numbers_1関数(短い方)ですよね。誰が見ても感じるんじゃないかなぁ。
2つの関数を見て、私は以下のように思いました(一色)。
extract_even_number_0関数は、行やインデントで構造が分かりやすいものの、リストを用意してappendするスタイルがダサい書き方だと思いました。C#ならこれが普通ですが。
extract_even_numbers_1関数は、左から順に読めば問題なく理解できますが、「number(s)」という単語が続くのが読みづらく感じるので工夫が必要です。例えば、[n for n in numbers if n % 2 == 0]とした方が読みやすいですね。n for nとなってしまうのは、Pythonのリスト内包表記の文法がそもそもイケテないからだと思います。
とはいえ、個人的にはどちらで書いても同じぐらいの複雑さに感じますね。だからどっちで書いてもよく、ケース・バイ・ケースで書き分ければよいのではないかとは思います(あとで説明します)。
そもそも「Pythonic」という語が意味するものは何なのでしょう。英語版のWikipediaの「Python」に関するページでは次のように書かれています。
"Pythonic" code may use Python idioms well, be natural or show fluency in the language, or conform with Python's minimalist philosophy and emphasis on readability.
日本語に意訳してみると「PythonicなコードとはPythonのイディオムをうまく使って、Pythonで書いたコードとして自然でヘンなところがなく、そのミニマリストな哲学に従っており、可読性を高めている」コードのことと考えられます(ホントに意訳なので、ツッコミはお待ちしていません)。
上のコードを例としたら「Pythonのイディオム」とはもちろんリスト内包表記のことです。Pythonに慣れてきたら、内包表記は自然と使えるようになるでしょうし、脳がPythonで考えるようになれば、スラスラと内包表記が出てきます。誰かが書いた内包表記入りのコードを見ても、その意味はスラスラと頭の中に入ってきます。
たぶん、「明確さ」と「Pythonic」の間には少しの距離があるのでしょう。あと、「明確さ」と「可読性の高さ」の間にも少し距離がありそうです(少なくとも初心者にとっては)。
そこでChatGPTさんに上の2つの関数を示した上で、明確さと可読性について聞いてみると、次のような答えが返ってきました。
まとめにある「明確さと可読性のバランスが取れたコード」というのが全てかもしれません。extract_even_numbers_0関数(長い方)は明確かもしれませんが、冗長だし簡潔ではありません。冗長だし簡潔でないというのは、一目でそのコードが何をしているかを理解できないと言い換えられるでしょう(この例ではそんなことはないですが)。それは「可読性が高いとは言えない」につながるのかもしれません(この例ではそんなことはないですが。2回目)。
というわけで、Pythonに慣れて、Python独自のイディオム(内包表記やジェネレーター、デコレーター、特殊メソッド、etc)を使いこなせるようにいろいろな経験を積んでいくことが、Pythonicなコードを書き、読み、理解するために必要なことなのかもしれませんね。
明確さと可読性は、私が考えたことそのままでした。かわさきさんと同じ内容になりますが、私の考えも話しておきます。
意図を分からせる必要がある場合ならextract_even_number_0関数で書いた方がいいです。アルゴリズムの勉強をしているなら上ですね。よって「初心者にとってアルゴリズムを理解するため」(=明確さ)という前提付きなら、確かにかわさきさんが最初に示した気付きに賛成です。
一方で、開発の現場で効率的に書くなら、例えばリスト作成の近似パターンが100回続くなら、断然、extract_even_numbers_1関数で書いた方がいいです。100個のforループよりも100個のリスト内包表記の方が、「比較しやすくなり実装ミスを見つけやすくなる」(=可読性)と思うからです。
まとまったようなまとまってないような気がしますが、今日はここまで!(笑)
Copyright© Digital Advantage Corp. All Rights Reserved.