« 2023年5月 | トップページ | 2023年7月 »

2023年6月30日 (金)

東京出張ついでに秋葉原 & 靖国神社へ行ってきました

やっとこさ、帰ってきました。

東京へ行くのは、昨年の8月以来。ですが、出張でしかも泊りがけというのは実に3年半ぶりです。

Img_3283

が、すでに出発時点で波乱に富んだスタートでした。写真ではわかりづらいですが、豪雨でした。

Img_e3287

雨天レーダーで見るとこう。ちょうどこの時、紫のところで覆われてましたね。駅のホームに屋根がついてますが、ほとんど役に立ってません。水しぶきがホームの奥まで飛び散り、結構濡れました。

そのおかげか、3分ほど遅れて電車が到着。

で、名古屋駅について気付いたんですが、東海道線が大垣~岐阜間で不通になってまして。

どうやら、すげえ大雨で電車が動かないんだとか。
えっ、ちょっと待って、そこって新幹線がほぼ並走してるじゃん。こっちも遅れるんじゃねぇ?

と思ったんですが、なぜか新幹線は平常運転。なんか、変な感じです。

Img_3291

とはいえ、御覧の通り260メートルほどあるミッドランドスクエアのてっぺんに雲がかかってました。こんなに低い雲に覆われるのを見るのは、久しぶりです。

途中、名古屋駅を出た直後と、浜松付近ですごい豪雨に見舞われました。が、東京についてみると、嘘のように晴れてます。

Img_3313

で、今回降りたところは、船堀というところ。

Img_3315

この駅の真向かいに、タワーホール船堀というところがありまして。

Img_3318_20230630221901

そこで行われる品質工学研究発表大会に参加するためにやってきました。

ちなみにこれ、2日間にわたって実施。

中身について説明するのはなかなかハードなので、ちょうどYouTubeでこの辺のことを解説している動画が公開されているので、それのみを紹介しておきます。

お分かりいただけだだろうか……?

若干、しゃべり方が痛いですが、分かりやすい動画ではあります。

Img_3324_20230630222601

ちなみに、今回のお供はこのSurface Go。小型で軽いうえに、バッテリーの持ちも上々なので、重宝しました。
あとはiPhone、Google Pixel 6a、そして充電器とモバイルバッテリーです。

Img_e3406

ちなみに、6時から9時にかけて猛烈な勢いでバッテリーが減ってます。

雨だったことも関連しているかもしれませんが、現地に着いてからも、ホール内での電波の受信が悪くて、それがバッテリー消費を挙げてしまった要因かもしれません。

ということで、モバイルバッテリーが活躍しました。

さてそんな1日目の終了後は、そのまま都営新宿線に乗り、岩本という駅で降ります。

Img_3331_20230630222101

で、橋を超えて、一路、秋葉原へ行きます。

Img_3339_20230630222201

秋葉原に着いてまず訪れたのは、この千石電商と

Img_3342_20230630222201

秋月電子通商です。

Img_3344_20230630222301

ところで、秋月電子は最近、2階ができたと聞きました。このいかがわしいポスターが出迎えてくれます。
やや2階へ行くのを躊躇わせる雰囲気ですが、頑張って階段へたどり着くと、

Img_3346_20230630222401

はい、確かにありました。スピーカーなどが売られてましたね。その代わり、1階店舗の外に置かれている量が減った気がします。

Img_3349_20230630222401

もちろん、BEEPにもいきました。

Img_3351_20230630222501

秋月電子の2階よりも、ある意味アグレッシブな階段ですね。ここで慣れている私に、秋月電子の2階など死角ですらなかった。

Img_3352_20230630223101

ところが今回、もう一つ寄る場所がありました。

それは、ちょうどBEEPのある場所から、中央通りを挟んで反対側。

Img_3355

このビルの谷間へと入り、

Img_3357_20230630223201

さらにその中ほどにある細いビルの谷間をくぐると、

Img_3359_20230630223201

なんと、神社があります。花房稲荷神社、というところだそうです。

私も最近、この存在を知ったんですが、どうやら秋葉原の隠れスポットのようですね。ちょうど外国人の方が訪れておりました。勇名みたいですね。

これ以外にも数か所、回った後に、

Img_3371

秋葉原駅前にある「モーゼスさんのケバブ」というお店でケバブを夕食としていただき、ホテルへと向かいます。
なお、このケバブは美味しいですが、ちょっとお店がなかなかな雰囲気です。

Img_3384

再び岩本町駅から都営新宿線に乗り、馬喰横山という駅で降ります。

その駅そばの、アパホテルがこの日の宿泊場所。

Img_3393

こじんまり、というか、部屋のほとんどがベッドというビジネスホテルです。まあ、可もなく不可もなく、といった感じ。

東京都内のど真ん中ですが、「アパ直」というアプリを使えば8000円で一泊できます。しかもこのアプリ、チェックイン時にQRコードを表示してカウンターの機械に通せば即、チェックインできます。安いうえに、便利でした。

Img_3409_20230630224101

ちなみに、窓からはスカイツリーが見えました。

Img_3401

ありとあらゆる電子機器を使ったので、早速充電です。今回も、昨年東京へ行く前に買った65WのUSB電源が大活躍でした。

Img_3421

で、翌30日も同じ場所で発表大会があったので参加。
ちなみに、昼飯は2日続けて、船堀駅すぐ脇にあった蕎麦屋さんで、冷やしおろしそばでした。なんか食欲場微妙だったので、これはなかなかはまりました。

なお、一日目は晴れてたのに、二日目は雨でしたね。

Img_3423

で、2日目は少し早めに終わったので、思い切ってこの「九段下駅」までやってまいりました。

どうして、この駅なのか?

Img_3427

はい、すぐそばにこういう場所があります。

「靖国神社」ですね。

そういえば、一度も行ったことがないなぁと思い、今回ちょっと足を延ばしていってみることにしました。

Img_3435

無論、本殿もいきましたが、

Img_3447

どちらかというと、その脇にある遊就館の方へ行きたかったんです。

Img_3452_20230630224601

ここにある零式艦上戦闘機52型、通称「ゼロ戦」を見ておきたかった、というのがあります。

よくよく考えたら、実物の復元ゼロ戦を見るのは初めてですね。

Img_3467

写真ではわかりづらいですが、想像以上に迫力があります。

なお、奥には桜花や回天、彗星などがあるんですが、あまり時間がなかったので、売店で買い物だけして帰りました。

Img_3479

で、東京駅に到着し、

Img_3487

東京一番街という地下街で、またジャンクフードで夕食を摂り、

Img_3491_20230630224901

一路、名古屋へと帰還します。

Img_3492_20230630225001

さて、今回の戦利品です。秋葉原に靖国神社、そして品質工学会の発表会と、多岐にわたる内容ゆえに、ほんと色々です。

左下にある帽子のようなものは、帽子です。靖国神社にて購入した、海軍第一種戦闘帽(冬用)というんだそうです。

Img_3494

写し忘れましたが、他にもゼロ戦のクリアファイルに、

Img_3496

日の丸扇子も購入。

Img_3509

これは、秋月電子で買った「フレキシブルLED」というやつ。とりあえず、3色(赤、黄、青)を買っておきました。

Twitterで見て面白そうだったので買ったんですが、使い道はないかなぁ。
なお、ワイヤレスLEDも欲しかったんですが、それは見当たりませんでした。

Img_3510

で、こちらは千石電商で買ったRaspberry Pi Pico。

そういえば、初めてPicoを買いました。そのうち、先のフレキシブルLEDと共に使おうかと。

Img_3511_20230630225501

これはBEEPで買った「ちょっとは正しいゲームの歴史」という同人誌です。
最近「ゲームの歴史」という本の中身があまりに酷いと炎上してましたが、これはそれを批判、訂正するという趣旨の本のようです。

Img_3514_20230630225701

が、中身を見ると、「ゲームの歴史」の何ページ目にある記述に問題があるか、をずらっと列挙して、続いて正しい情報を書く、というスタイルの書籍でした。

ということは、「ゲームの歴史」という本を買って並べてみないといけないじゃないか。うん、批判本といいつつもちゃっかりその本の購入動機を与えてしまっているのは優しい。

Img_3512

一方のこちらは、靖国神社で購入した「英霊の言の葉」という冊子。

Img_3513_20230630230401

これは、硫黄島で玉砕した指揮官の栗林陸軍大将の最後の突撃前の電報です。
こんな具合に、戦場からの手紙や遺書などがつづられた冊子です。
この方々の先に、我々の今があることを、忘れないようにしたいものです。

という感じに、何気に充実した出張でした。おかげさまで結構、散財しましたが。
さて、次に東京へ行くのはいつの日か?

そもそも品質工学 実験No.1

2023年6月25日 (日)

OneDrive ⇔ PCローカルの大量ファイル同期作業

表題の通り、メインPCとOneDriveとの同期作業をやってます。

と、まずは我が家のファイル事情(特に写真データ)について説明。

20230625-161219

ざっくり言うと、写真・動画に関しては「dcdata」と「カメラロール」の2つがあって、

・ dcdata ・・・ 2000年以降、デジカメ等で撮影した画像が集約されているフォルダ

・ カメラロール ・・・ 2021年6月以降、OneDriveを導入して以来、iPhone等から直接アップロードされた写真の入ったフォルダ

という構成です。

で、一応、dcdataは手動で同期をかけてたんですが、なんか面倒になってきたのでそろそろ自動で同期させたい。

加えて、カメラロールの画像をPCに取り込んでおきたい(OneDriveを解約するときに備えて)。

先日、SSDを2TBに変えた(メインPCのストレージをキオクシア製2TB NVMe M.2 SSDにしてみた: EeePCの軌跡参照)ので容量に余裕が出たため、この2つの事情をかなえるべくOneDriveとPCローカルの同期を行うことにしました。

が、一つだけ厄介な事情があって。

メインPCのDドライブには512GB SSDがついてて、そこにも「dcdata」フォルダが入ってます。

が、この中には先日、DVD-RAMは最強のバックアップメディアか!?: EeePCの軌跡の記事でも書いた通り、DVD-RAMからサルベージした動画ファイルを入れてあります。
で、この動画ファイル自体は、OneDriveとは同期されておりません。

なら、動画ファイルを同期すればいいじゃないか、という話なんですが、それが少々厄介なことに、dcdata内にある470個以上のフォルダのどこかに入っている状態で、人間業では探し出せなくなってます。

20230625-160138

さて、どうしたものか……

で、今の状況とやりたいことをまとめると、こんな感じ。

20230625-163312

てことで、このややこしい状況で、OneDriveとPCローカルを完全同期させます。

このためには大きく分けて、「OneDrive ⇔ PCローカル」と「フォルダ同士」の2つの同期手順があります。

(1) OneDriveとPCローカルの同期設定

OneDriveとPCローカルの同期設定ですが、まずスタートアップで「OneDrive」が起動できていなかったので、これを設定。

これは簡単で、「設定」-「アプリ」-「スタートアップ」の中にある「Microsoft OneDrive」をオンにするだけです。

これを有効にするため、一度ここで再起動します。

さて、通常ですと「C:¥Users¥(ユーザー名)¥OneDrive」があって、その中にクラウド上のOneDriveのファイルが入っております。

が、デフォルトではOneDrive内のファイルのショートカットが入っている状態に過ぎず、ここに実ファイルが入るよう設定する必要があります。

Windows 11では、タスクバーにあるOneDriveのアイコン(雲のマーク)を右クリックすると、下のように歯車アイコンが出てきます。

20230625-165902

このアイコンをクリックして「設定」を選択、「同期とバックアップ」の下にある「詳細設定」をクリックします。

20230625-170154

その中にある「すべてのファイルをダウンロードする」をクリックすると、同期が開始されます。

これであとは放っておけば、OneDrive ⇔ PCローカルは自動的に同期されます。

20230625-160253

ただ、うちの場合は400GB以上あるので、結構時間かかります(今、ちょうど裏で動いてます。一晩以上はかかるかな)。

(2) 大量フォルダ同士のファイル同期

この同期作業には、昔から使っている「Realsync」という同期ソフトを使います。

RealSync

20230625-160546

個人的には、動作も早くて設定も分かりやすいので、重宝してます。

20230625-160645

今回は、D:¥dcdataにあるファイルをC:¥Users¥(ユーザー名)¥OneDrive¥dcdataにコピーさせたいので、上のような設定にしておきます。

この状態でOKを押して、「今すぐ同期」をクリック。

SSD同士なためか、10GB以上の差分ファイルの同期はものの数分で終わりました。

で、あとは上の自動同期で、OneDriveとも同期してくれれば終了です。

ということで、PCローカルとクラウドの同期設定はどうにかできましたが。

あとはローカルPCをフルバックアップできるドライブをつけてやれば、ローカル側の故障にも対応できます。

2TB HDDはあるんですが、PCのローカルに入れていないファイルとかもあって、ちょっと足りないんですよね。

次は、2TBよりも大きいHDDを買って、同期設定ですかね。


BUFFALO ミニステーション USB3.1(Gen.1)/USB3.0用ポータブルHDD 5TB HD-PCFS5.0U3-GBA

2023年6月20日 (火)

Apple Watch Series 1の画面が!

なんか、でかいドット抜けを発見したんです。

Pxl_20230619_215307113

ベル型アイコンのある赤い領域の端に、黒い大きな点が見えます。
以前にはこんなものがなかったので、ここ最近できたものと思われます。

となると、他にもドット抜けが起きていないか気になるところ。

そこで、Apple Watchをフラッシュライトモードにして、画面を真っ白にしてみたところ……

Pxl_20230619_215329836

うぎゃあ!

分かりますかね、画面の縁がぐるりと一周、何やらにじんでます。特に右と下が酷いですね。

どうやら、Apple Watchのディスプレイがイカレ始めたようです。

そういえばこのApple Watch、いつ購入したのかと調べてみたら。

Apple Watch Series 1を買いました: EeePCの軌跡

2018年7月だったんですね。まもなく5年になります。
その前の初代Apple Watchが2年半で寿命だったので、それと比べたらかなり長持ち。
ですが、バッテリーよりも先に、ディスプレイから不調になってくるとは……

しかし、なぜディスプレイがこうなってしまったのか?

思い当たるとすれば、通知を消去するためにグッと指で押すんですよね。いわゆる感圧パネルなので、それを繰り返しております。

その歪みが溜まった結果かもしれません。

とはいえまだ使えるので、しばらくはこのままでいくつもりですが、完全に壊れる前に購入した方がいいかもと思ってます。
というのも、最近も突然、身体が不調になることがあって、心拍数は取っておきたいんですよね。

うーん、今ならSeries 8がいいのか、それともSEの方で十分なのか。悩ましいところです。

Apple Watch SE(第2世代) GPSモデル、 40mmケース ミッドナイトアルミニウムケースとミッドナイトスポーツバンド レギュラーを組み合わせたスマートウォッチ。フィットネストラッカーと睡眠トラッカー、衝突事故検出、心拍数のモニタリング、Retinaディスプレイ、耐水性能

2023年6月18日 (日)

杉井光「世界でいちばん透きとおった物語」を読んだ

タイトルにある通りです。「世界でいちばん透きとおった物語」という小説を読みました。

Img_3280

とあるアニメ紹介を主にやっているYouTuberさんのチャンネルで、この小説のことを知りました。

この動画中でも述べられているのですが、この小説はとにかく「ネタバレ厳禁」「紙の書籍でしか作りえない作品」です。
なんてことをおっしゃるので、とにかく気になって仕方がない。とりあえず、これを見たその週末に書店へ出向いたのですが。

ない!!

そう、この動画で紹介された直後に、売り切れ続出であらゆる店頭から消えてしまったとのことです。タイトル通り、透きとおってしまった、と言うわけではありません。恐るべし、YouTuberの影響力。
で、しばらくは入手できずに悶々としておりましたが、ようやく書店で並び始め、先日やっと入手しました。

にもかかわらず、一週間ほどは買ったままほったらかしにしてたんですが、この週末にやっと開き、そして一気に読み終えました。

で、読んだ感想ですが。

全部で13章からなる小説ですが、その12章を読むあたりから、この作品の脅威さを思い知らされます。

ああ、確かにこれは、紙の書籍でないと無理だわ。

そして「世界でいちばん透きとおった」のタイトル回収。

そのすべてを悟ったとき、もう一度この本を見直すと、背中からゾゾッと寒気がします。えっ、そこまで考えて書いた本なの!?
最後のページには、さすがにからくりはないか……と油断していると、実は仕込まれていた、何てのもあります。

まあ、そういう本だった、ということだけを、お伝えします。

内容的には推理小説というカテゴリーになるんでしょうけど、その謎かけの方向がかなりぶっ飛んでます。

にしても、恐るべきアイデアですね。私も一応、小説家になろうで作品を挙げている身ではありますが、こんな考えを思いつくことすらあり得ない。いや、小説家になろうでは再現不能です。

まあ、帯にもある通り「ネタバレ厳禁」なので、気になる方はぜひ、手に取って読まれることをお勧めします。


世界でいちばん透きとおった物語 (新潮文庫 す 31-2)

2023年6月17日 (土)

JVC BN-RB10CでメインPCを動かしてみた

先日の記事「完璧で究極の(!?)大容量バッテリー「JVC BN-RB10」を買った: EeePCの軌跡」でも紹介したあの大型モバイルバッテリーで、うちのメインPCであるGALLERIA GR1650TGF-Tを動かしてみました。

Img_3259

といっても、ノートPCなのでさほど出せないはずですが、まあ、使い方によってどれくらい持ちそうか試してみるのもいいかなと。

Img_3260

電源接続し、スイッチオン。

Img_3261

ちなみに、充電状態で30W程度でした。

Img_3262

では早速、ぽちっとな。

Img_3263

すぐに起動しますが、この時の消費電力が。

Img_3265

70~80W程度でした。
撮り忘れましたが、しばらく放っておくと、30~40W程度まで下がります。

Img_3272

ここで、高負荷をかけてみます。真っ先に思いついたのは「Stable Diffusion WebUI」です。
紹介しておりませんでしたが、最近、こいつにいろいろと描かせてます。

Img_3271

結構いきましたが、120W程度ですね。こんなもんかしらん?
GPUは目一杯使いますが、CPUはせいぜい20%程度なので、本当の実力とは言い難い模様。

20230617-092202

最近はまっていた言語系の生成AIで、Dolly 2.0を使ってみました。
こいつなら、メモリーもガバガバ食って結構いきそう。

Img_3273

……と、思いきや、思いの外、消費電力は少ないです。せいぜい80W程度でした。
ファンが全開で回ってるので、結構使っているのかと思いきや、言語系の生成AIってメモリーは食うけどCPU、GPU共にほとんど食わないんですよね。

Img_3274

CPUとGPUを同時に使いそうなやつ、なかったかな?と考えて思い出したのは、こちらの「VR戦艦大和」。
そういえば、こいつはグラフィックも使うし、そこそこCPUも使うから、結構いくのでは?

Img_3275

てことで、早速やってみました。左弦(ひだりげん)、目標艦見ゆ、射撃よーい!

Img_3277

撃ちーかた始め!

Img_3276

と、派手に撃ちまくってますが、Stable Diffusionとさほど変わらず110~120W程度。

この時点でようやく電源の方を見てみたんですが、最大出力は120Wと書かれてました。てことは、これでほぼ目一杯だったんですね。
結局、1時間ほど動かしましたが、92 → 85%と、ほとんど減りませんでしたね。このペースなら14時間くらいは使い続けられそうです。

ちなみに、取説には1000Wなら40分使えると書かれていたので、100W出力を出し続ければ400分、つまり7時間弱で電池が切れます。が、実際にはアイドル運転の方が長いので、その倍は使えそうな模様です。

これでも、ノートPCとしてみると結構消費電力は多い方ですけどね。会社のPCなんて、45W電源で動いてますし、うちのSurface Goに至っては20W程度の電源で動きます。こっちならもっと長時間運転が可能ですが、標準バッテリーでも長持ちするので、わざわざこのバッテリーを使うかどうか。

重さ10kg程度のバッテリーですが、屋外でゲーミングPCを長時間使いたいという向きには、十分に答えられるだけの容量はありそうです。


JVCケンウッド ポータブル電源 BN-RB10-CA 充電池容量 278,400mAh/1,002Wh

2023年6月12日 (月)

完璧で究極の(!?)大容量バッテリー「JVC BN-RB10」を買った

誰もが目を奪われていく
君は完璧で究極のバッテリー!

Img_3244

……と言えるほど究極のバッテリーと言うわけではありませんが。ただ、これを近所のエディオンから持ち帰る時は、結構見られてました。多少の目は奪ってます。
そして、我が家では最強のバッテリーであることには間違いありません。

この箱絵にもある通り、その容量はなんと1002Wh
最大出力は1000Wで、電子レンジも動かすことが可能。

ちなみに、これまで持っていた我が家最大のバッテリーは、18W出力な10000mAhのモバイルバッテリーで、その容量は37Wh
桁が二つ違いますね。こいつの前では、ゾウの前のハムスターです。

なお、重さは10.9kg。ちなみにお値段は15万円超でした。

Img_3245

中身はこんな感じ。バッテリー本体に、ACアダプターとシガライターソケットケーブル。車からも充電が可能なようです。多分、使わんけど。

Img_3246

ちなみに、買った時点では42%でした。

Img_3247

で、とりあえずそばにあった扇風機を回してみます。

Img_3248

うーん、余裕ですね。27Wです。

もちろん、我が家のメインPCであるゲーミングノートPCでも、せいぜい150W電源なので、これも余裕でしょうね。
もっと派手なやつでテストしたいところ。

Img_3250

はい、あります。大出力なやつが。
アイリスオーヤマ製のコンパクトなクーラー。出力600Wです。

ちなみに、このバッテリーを買った理由は、災害時の停電に備えてのこと。
うちの妻が、暑いのがまるでダメなので、それでこのクーラーと共に揃えました。

Img_3251

てことで、動作開始。
当たり前ですが、余裕で動きます。

Img_3255

出力は、ほぼ定格の593Wでした。電子レンジ並みですが、ちゃんと動きますね。
が、500W程度の出力だと、満充電でも動かせるのは80分程度。この程度の非常電源で、本当に役に立つのかどうかはやや疑問ではありますね。
でもまあ、扇風機なら30W程度なので、これならほぼ一晩でも余裕で動かせそうです。

Img_3254

もちろん、USB電源もあります。こちらは「DC」のスイッチを押して使います。
最近のノートPCならUSB-C駆動が可能なので、これにつないで使えます。そういえば、会社PCもUSB-Cで駆動可能なので、在宅勤務時にYogiboで仕事したくなったら、これを使えばいいか。

Img_3257

さて、充電ですが、先ほどのACアダプターの端子を、前面のここに挿します。

Img_3258

充電時の出力は145Wほど。この状態で、4、50ほど放置しておいたら、7%ほど増えてました。一晩もあれば、充電できるペースかなと。

機能的には、家電やPC、モバイル機器を動かすというだけのものですけど、ちょっといいなと思うのは、消費電力が見えることですかね。
だいたいこいつ、どれくらいの消費電力なんだろうかと疑問に思うこともありますが、そういう時はこいつにぶっ刺して動かしてみればわかるというわけです。

またしばらく使ってみて、レビューします。


JVCケンウッド ポータブル電源 BN-RB10-CA 充電池容量 278,400mAh/1,002Wh

2023年6月 3日 (土)

「深層距離学習」をお手軽??に体験できるプログラムコード書いた

ChatGPTやStable Diffusion等の生成AIが大流行りですが、少し原点に戻って、畳み込みニューラルネットワークな話をします。

といっても、ただの画像認識ではなくて、metric learning、すなわち「距離学習」をやります。
以下、プログラムコードを含めて参考にしたのは、以下のサイト。

【深層距離学習】Center Lossを徹底解説 -Pytorchによる実践あり-|はやぶさの技術ノート

例えば、よく画像分類の初歩で使われる「MNIST」(えむにすと、と読みます)という手書きの数値が大量に集められた画像セットがあります。

20230603-175358

0から9までの10種類の手書きの数字データなんですが、これをいかに正確に分類するかという学習をやるために、いわゆる「畳み込みニューラルネットワーク(CNN)」という手法を用います。

が、これを通常のCNN手法で分類すると、こんな感じになります。

0

全部で10種類のデータがきれいに切り分けられている(つまり、分類が上手くいっている)ことを示している図なのですが、なんだか気持ち悪いところがあります。
それは、原点からしゅーっと伸びたような、妙なデータ分布をしているということ。

こういう広い許容範囲を持っていると、例えば0から9までの数値とは似ても似つかない文字(アルファベットのAなど)を入力しても、強引に0から9に解釈されてしまいます。

0から9までの数値と、それ以外の文字を分けるためには、以下のような感じの分類が望ましいです。

Epoch100

それぞれの数値の分類が、綺麗に分かれています。
こんな具合に、分類の距離を離してやることで分類のブレをなくしてやろうという手法が「距離学習」です。
(かなーり大雑把に説明していますが、そんなようなものだと思ってください)

例えば「1」という手書きの数字が入力されたら、機械学習モデルを通して得られた出力データは、この色のついた点群のどこかに収まるはずです。

逆に数字ではない「A」のような文字が入力されたら、この点群とはまったく別のところにプロットされるはずです。

というのを、実際に体感してみましょう、というプログラムです。

今回のプログラムですが、Jupyter notebookで作成したため、ブツ切りとなってます。
そのままコピーして一つにまとめて動かしていただいても大丈夫なはずです。

まずは、必要なライブラリから。


import os
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from  torch.utils.data import DataLoader
import torch.optim.lr_scheduler as lr_scheduler
import matplotlib.pyplot as plt
from torchinfo import summary
from torch.autograd.function import Function
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

%matplotlib inline

pytorchで動かしてます。ちなみにバージョンは1.12.1です。
pytorchのインストール方法は、以下を参照。

Previous PyTorch Versions | PyTorch

他には、numpy、torchinfo、matplotlibが必要です。


epochs = 100 # 繰り返し回数

use_cuda = torch.cuda.is_available() and True
device = torch.device("cuda" if use_cuda else "cpu") # CPUかGPUの自動判別
 
if not os.path.exists("images"):
    # ディレクトリが存在しない場合、ディレクトリを作成する
    os.makedirs("images")

初期値を設定します。GPUが使える環境か否かを、自動判別させてます。


class CenterLoss(nn.Module):
    def __init__(self, num_classes, feat_dim, size_average=True):
        super(CenterLoss, self).__init__()
        self.centers = nn.Parameter(torch.randn(num_classes, feat_dim))
        self.centerlossfunc = CenterlossFunc.apply
        self.feat_dim = feat_dim
        self.size_average = size_average

    def forward(self, label, feat):
        batch_size = feat.size(0)
        feat = feat.view(batch_size, -1)
        # To check the dim of centers and features
        if feat.size(1) != self.feat_dim:
            raise ValueError("Center's dim: {0} should be equal to input feature's \
                            dim: {1}".format(self.feat_dim,feat.size(1)))
        batch_size_tensor = feat.new_empty(1).fill_(batch_size if self.size_average else 1)
        loss = self.centerlossfunc(feat, label, self.centers, batch_size_tensor)
        return loss

class CenterlossFunc(Function):
    def forward(ctx, feature, label, centers, batch_size):
        ctx.save_for_backward(feature, label, centers, batch_size)
        centers_batch = centers.index_select(0, label.long())
        return (feature - centers_batch).pow(2).sum() / 2.0 / batch_size

    def backward(ctx, grad_output):
        feature, label, centers, batch_size = ctx.saved_tensors
        centers_batch = centers.index_select(0, label.long())
        diff = centers_batch - feature
        # init every iteration
        counts = centers.new_ones(centers.size(0))
        ones = centers.new_ones(label.size(0))
        grad_centers = centers.new_zeros(centers.size())

        counts = counts.scatter_add_(0, label.long(), ones)
        grad_centers.scatter_add_(0, label.unsqueeze(1).expand(feature.size()).long(), diff)
        grad_centers = grad_centers/counts.view(-1, 1)
        return - grad_output * diff / batch_size, None, grad_centers / batch_size, None

Center Lossというものを定義します。
通常、画像分類ではSoftmax Lossが最小となるように最適化計算をしますが、これに加えてこのCenter Lossというものを最小化することで、距離学習を行います。

すごくざっくり言うと、0から9までの10種類の手書き数字の出力データ群の中心を離し、それぞれがその中心に寄せるように学習させるためのLoss値ということのようです。だからCenter Lossと言うようで。


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1_1 = nn.Conv2d(1, 32, kernel_size=5, padding=2)
        self.prelu1_1 = nn.PReLU()
        self.conv1_2 = nn.Conv2d(32, 32, kernel_size=5, padding=2)
        self.prelu1_2 = nn.PReLU()
        self.conv2_1 = nn.Conv2d(32, 64, kernel_size=5, padding=2)
        self.prelu2_1 = nn.PReLU()
        self.conv2_2 = nn.Conv2d(64, 64, kernel_size=5, padding=2)
        self.prelu2_2 = nn.PReLU()
        self.conv3_1 = nn.Conv2d(64, 128, kernel_size=5, padding=2)
        self.prelu3_1 = nn.PReLU()
        self.conv3_2 = nn.Conv2d(128, 128, kernel_size=5, padding=2)
        self.prelu3_2 = nn.PReLU()
        self.preluip1 = nn.PReLU()
        self.ip1 = nn.Linear(128*3*3, 2)
        self.ip2 = nn.Linear(2, 10, bias=False)

    def forward(self, x):
        x = self.prelu1_1(self.conv1_1(x))
        x = self.prelu1_2(self.conv1_2(x))
        x = F.max_pool2d(x,2)
        x = self.prelu2_1(self.conv2_1(x))
        x = self.prelu2_2(self.conv2_2(x))
        x = F.max_pool2d(x,2)
        x = self.prelu3_1(self.conv3_1(x))
        x = self.prelu3_2(self.conv3_2(x))
        x = F.max_pool2d(x,2)
        x = x.view(-1, 128*3*3)
        ip1 = self.preluip1(self.ip1(x))
        ip2 = self.ip2(ip1)
        return ip1, F.log_softmax(ip2, dim=1)

続いて、ネットワークです。MNISTは28 X 28のモノクロ画像なので、非常に小さいネットワークで構成されてますね。
なお、ip1というのは畳み込みニューラルネットワークから結合層となった直後に出力値を使い、それを二次元化した特徴ベクトル、ip2というのは10次元のベクトルで、Softmaxをかける前の出力ベクトルのようです。


def visualize(feat, labels, epoch):
    c = ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff',
         '#ff00ff', '#990000', '#999900', '#009900', '#009999']
    plt.clf()
    for i in range(10):
        plt.plot(feat[labels == i, 0], feat[labels == i, 1], '.', c=c[i])
    plt.legend(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], loc = 'upper right')
    plt.xlim(xmin=-8,xmax=8)
    plt.ylim(ymin=-8,ymax=8)
    plt.text(-7.8,7.3,"epoch=%d" % epoch)
    plt.savefig('./images/epoch=%d.jpg' % epoch)

そしてこのvisualizeという関数は、特徴ベクトルの出力点群をグラフ化し、画像として残すためのアルゴリズムです。最初に出したカラフルな点群グラフは、これで作られてます。


def train(epoch):
    print("Training... Epoch = %d" % epoch)
    ip1_loader = []
    idx_loader = []
    for i,(data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)

        ip1, pred = model(data)
        loss = nllloss(pred, target) + loss_weight * centerloss(target, ip1)

        optimizer4nn.zero_grad()
        optimzer4center.zero_grad()

        loss.backward()

        optimizer4nn.step()
        optimzer4center.step()

        ip1_loader.append(ip1)
        idx_loader.append((target))

    feat = torch.cat(ip1_loader, 0)
    labels = torch.cat(idx_loader, 0)
    visualize(feat.data.cpu().numpy(),labels.data.cpu().numpy(),epoch)
   
    torch.save(model.state_dict(), './mnist.pth')
    return feat, labels

で、こちらは学習用の関数。最後に「mnist.pth」という名前でモデルを保存します。


# Dataset
trainset = datasets.MNIST('./MNIST', download=True,train=True, transform=transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))]))
train_loader = DataLoader(trainset, batch_size=128, shuffle=True, num_workers=0)

# データセットの一部を可視化
data_iter = iter(train_loader)
images, labels = data_iter.next()
# matplotlib で1つ目のデータを可視化
for idx, _ in enumerate(labels):
    plt.figure(idx+1)    
    npimg = images[idx].numpy()
    npimg = npimg.reshape((28, 28))
    plt.imshow(npimg, cmap='Greens')
    plt.title('Label: {}'.format(labels[idx]))

ここからは、メイン処理に入ります。
初回のみMNISTのデータセットをダウンロードし、「MNIST」というフォルダに入れます。

一応、中身を確認したいと思ったので、一部を表示させてます。

20230603-174110

こんな表示がずらずらっと出てきます。


# Model
model = Net().to(device)

summary(model)

続いてモデル定義です。summaryのところで、ネットワーク図と各層のパラメータ数を表示させてます。

=================================================================
Layer (type:depth-idx) Param #
=================================================================
Net --
├─Conv2d: 1-1 832
├─PReLU: 1-2 1
├─Conv2d: 1-3 25,632
├─PReLU: 1-4 1
├─Conv2d: 1-5 51,264
├─PReLU: 1-6 1
├─Conv2d: 1-7 102,464
├─PReLU: 1-8 1
├─Conv2d: 1-9 204,928
├─PReLU: 1-10 1
├─Conv2d: 1-11 409,728
├─PReLU: 1-12 1
├─PReLU: 1-13 1
├─Linear: 1-14 2,306
├─Linear: 1-15 20
=================================================================
Total params: 797,181
Trainable params: 797,181
Non-trainable params: 0
=================================================================

こんなのが表示されるはずです。


# NLLLoss
nllloss = nn.NLLLoss().to(device) #CrossEntropyLoss = log_softmax + NLLLoss
# CenterLoss
loss_weight = 1
centerloss = CenterLoss(10, 2).to(device)

そして、Loss関数を定義し、


# optimzer4nn
optimizer4nn = optim.SGD(model.parameters(),lr=0.001,momentum=0.9, weight_decay=0.0005)
sheduler = lr_scheduler.StepLR(optimizer4nn,20,gamma=0.8)

# optimzer4center
optimzer4center = optim.SGD(centerloss.parameters(), lr =0.5)

最適化手法を定義したら、


for epoch in range(epochs):
    sheduler.step()
    feat, labels = train(epoch+1)

学習開始です。

100サイクルほど回しましたが、我が家では大体30分ほどかかりました。

20230603-194654

最後にこんな感じの絵が出てくれば、終了です。

一応、各エポックごとの画像もimagesフォルダに出力されます。

Epoch3

3エポック目は、ほとんど未分離だった各分類が、

Epoch22

だんだんと別れ始め、

Epoch58

Epoch100_20230603203901

そして100エポックできれいに分かれました。
これくらい綺麗に分離できていたら、学習は終了です。

学習はここまでですが、ここで自分で作った手書きの画像データを使って、それを「推論」させてみます。

といっても、それぞれの画像が上の点群グラフの中でどのあたりに来るのか?を見るだけです。


def visualize_pred(feat, labels, out_feat):
    c = ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff',
         '#ff00ff', '#990000', '#999900', '#009900', '#009999']
    plt.clf()
    for i in range(10):
        plt.plot(feat[labels == i, 0], feat[labels == i, 1], '.', c=c[i])
    plt.plot(out_feat[0],out_feat[1], marker="*", markersize=30, markerfacecolor="r")
    plt.legend(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], loc = 'upper right')
    plt.xlim(xmin=-11,xmax=11)
    plt.ylim(ymin=-11,ymax=11)
    plt.text(-10.8,10.3,"test image")
    plt.savefig('./images/test_pred.jpg')

まずは、推論用の可視化関数を作ります。


test_model = Net()
test_model.load_state_dict(torch.load('./mnist.pth'))
test_model.eval()


# 画像の読み込みと前処理
image = Image.open('test_1.png').convert('L')
transform = transforms.Compose([
    transforms.Resize((28, 28)),
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])
image = transform(image)
image = image.unsqueeze(0)

# 推論の実行
with torch.no_grad():
    output = test_model(image)

output_xy = (output[0].data.cpu().numpy())[0]
print(output_xy[0], output_xy[1])

visualize_pred(feat.data.cpu().numpy(),labels.data.cpu().numpy(), output_xy)

ここで「test_1.jpg」という画像を読み込み、その結果をプロットさせます。
ちなみに「test_1.jpg」という画像は以下。

Test_1

はい、数字の「1」ですね。
これを推論させたら、どうなるか?

Test_pred_1

こうなりました。赤い星が見えるかと思いますが、それが先の画像の推論結果です。
ちなみに、黄色い点群が「1」で、この赤い星印はその黄色い点群の中にいます。
要するに、「1」だと認識されていることが分かります。

Test_aa

それじゃ、気を取り直してこんどは「あ」という文字をぶち込んでみます。
0から9の数字とは似ても似つかないこの文字、果たして結果はどうなるか?

Test_pred_aa

こうなりました。どの点群にも入らず、「1」と「5」の間よりちょっと原点寄りにいますね。
要するに、「その他」と認識されたってことですね。

Test_a

今度は、アルファベットの「A」を入れてみました。

Test_pred_a

うーん、「8」と「3」の間辺り?まあ、「その他」のゾーンですね。

Test_3

しかし、困ったのはこの数字の「3」。

Test_pred_3

うーん、原点から見れば、「3」の集団である水色の点群の先にいるんですが、ちょっと離れすぎちゃいませんかね?
実は、いくつかの手書き数字で確かめたんですが、この「3」のような微妙な結果になることが多かったです。

やや、過学習気味でしたかね?

とにもかくにも、距離学習をイメージできるプログラムができました。

ところで、今はこのCenter Lossと言うのはあまり使われていないようで、もっぱらよく使われるのは「SphereFace」、「CosFace」、「ArcFace」あたりでしょうか。このCenter Lossとはまた違う距離の離し方をしますが、分類ごとの距離を離すよう学習させるという点では同じようなものです。
詳しくは、以下をご参照願います。

モダンな深層距離学習 (deep metric learning) 手法: SphereFace, CosFace, ArcFace - Qiita

ちなみに、この深層距離学習というのは異常検知手法や顔認証のようなもので使われてます。私の場合はArcfaceを使って異常検知させるものをよく作ってます。はい。


物体・画像認識と時系列データ処理入門 [TensorFlow2/PyTorch対応第2版] NumPy/TensorFlow2(Keras)/PyTorchによる実装ディープラーニング

« 2023年5月 | トップページ | 2023年7月 »

無料ブログはココログ

スポンサード リンク

ブログ村