今更Stable Diffusionを動かす

Posted on

まぁ、その、暇だったので、はい。

Twitterで日々バトルが繰り広げられる学習側の権利や、生成物の権利云々に関しては、

古くは今の著作権の元となった福沢諭吉の主張した版権から繰り返された、「情報はコピーも改変も配布も容易」なことに纏わる話の変奏曲の一種で1、コンピュータの世界でなら、

のようなことを、また繰り返している。こういう穴をつくのは商売の世界ではありふれた話で、あとは文化庁で審議しつつ法律の整備待ちで、意見があるならTwitterで殴り合ってないで、パブリックコメントを出したり政治活動をしたり、訴訟して最高裁まで持ち込むなどするとよいのではないではないでしょうか、ここはなんとまだ民主主義国家なので、とだけ。

あぁ、もちろん法規制が整うまでに色々ビジネスやるのもよくある話です。ぼくから言えることは、ビジネス上の競合だけでなく、周りの警備会社の人や証券会社の人雇った社員も含めて、その他大勢の人に刺されないようにも、気を付けるといいかもしれませんね。じゃあな、ご武運を。

それは置いといて。逆に美術の「模倣とそれに対する人間のいさかい」の歴史にはうといので、ご存じの方が居たら教えてもらえると助かります。

あ、あと、逆に生成AIで作ったものに著作権が認められるか(著作物性があるか)に関してもまだ議論中ですが(文化庁の資料p.39)、とりあえずわたしはこの記事の中で、わたしが自分のマシンを使って生成した画像について著作権を主張するつもりはありません。

…というクソ長い前置きの元はじめます。

UIを動かすぞい

Stable Diffusionそのままだと雑に動かすのは大変だと思ったので、定番っぽい stable-diffusion-webui をうごかしました。

環境は以下:

  • Ryzen Threadripper 1950x
  • DDR4 64GB
  • Radeon 6800XT
  • Ubuntu 24.04
  • Python 3.12.3
  • Rust 1.82.0 via rust-init

もう7年くらい前のPC2で、今はsshでつなぐサブの開発用マシンになってるんですが、実はあんまり性能が足りなくて困るという事はなかったりします。PC、進歩ねぇなぁ。

基本的には動かし方のマニュアル通りに動かしました。コロコロ変わると思うのでいちいち記録にはしません。

案の定コケる

[Bug]: issue with tokenizers · Issue #16445 · AUTOMATIC1111/stable-diffusion-webui

ここにある不具合そのものに突き当たりました。コメントだとPython 3.10じゃないからではないかとか、rustcのバージョンが新しいから(!)ダメなのではないか、といった議論があるのですが、Rustに関してはIssueに「解決した」とされるver 1.65.0まで下げても同じエラーでしたし、そもそもコンパイルエラーは casting &T to &mut T is undefined behavior と正当に思えるものですから3、rustのバージョンはそのまま1.82.0のまま動かすことにしました。

結果として、次で(わたしの環境では)動きました。

  1. transformersのライブラリを上げる。
    requirements_versions.txt の transformersのところを`transformers==4.34.0`に変更する。
    このバージョンの依存関係(の依存関係?)にあるrustのソースの該当箇所はunsafeで括ってる(大丈夫なのかな…)
  2. transformersのあるAPIで同じ挙動をする(はず)の2つのパラメータの与え方があるので、もう1つの方に変更する

しれっと書いてますけど、3時間ぐらい掛かりました。別のYouTuberの限界分譲地の謎の雑談生放送を聞いてる時の暇つぶしにはちょうどよかったかな、とだけ。

(´-`).。oO(…なんか自分で描いた方が速くないか…)

Pythonの依存関係解決には、すこしだけ詳しく…なったような…。地獄ですねこれ。requirements.txtいい加減そろそろやめた方がいいんじゃない?w

こういうのを仕事として依頼したい時は、ぼくの会社の方にメールください(ダイマ)。もっとめんどくさくてもやるよ~(もちろんお金はもらいますけどもw)。

この件に関してプルリクを作ったのですが、このエラー自体はPythonとRustの、CPUの世界だけで閉じてるのですが、それでも環境によって起きたり起きなかったりするよくわかんない不具合のようで、一旦closeしました(後で書くけど、もうこのソフト飽きたので、ぼくがopenする事はないだろうが…)。2024年になっても、まだこんな感じなんですねぇ。もう2年経ったんだけどな。

出力するぞい

さて、ためしにFediverseの人が呟いてたジョークをそのまま入れました

この結果は、まさにおどろくべきものになりました。「ありがとう」という言葉を見せた水は明らかに、六角形のきれいな形の結晶をつくりました。それに対して「ばかやろう」の文字を見せた水は、結晶がばらばらに砕け散ってしまいました。そして、「masterpiece,best quality:1.4,super fine illustration,shiny skin,detailed skin,detailed face,detailed eyes,an extremely cute and beautiful girl,cowboy shot,beautiful face」という言葉を見せた水は、どこかで見たことがあるような美少女っぽい結晶をつくりました。
https://oransns.com/@Lincade/113386014063650493

この「呪文」自体はとりあえず最初に置いておくと効力を発揮する?ようで、このまんまの完全一致で検索を掛けるとこの後に色々自分で追加してる人が割と見つかります。「うらら迷路帖」で言うと「祝詞」みたいなもんだろな。…東西東西皆々さまに さあさあ八卦の八つ当たり4

さて占いの結果はこちら。ガチャなんでなんか蓮コラみたいになってるやつが最初出て来たんですが5、流石に貼る気にはなれなかったので何回か回した結果になります。ちなみにイラストか実写かはプロンプトにillustrationって書いてあるのにガチャでした。その辺はGANの頃と一緒かな。これは実写と言っていいでしょう。

「cowboy shot」に引っ張られてるのかカウボーイ(カウガール?)になってます。ウケますね。これ思い出したわ(2021年。リンク先は生成AI特有のグロ画像注意)、なつかし:

…元の話に戻る(?)と、Stable Diffusionは「水」以下ってとこですかね?どうおもいます?

ちちぷいの呪文を試しにそのまま入れる

天使ちゃん | chichi-pui(ちちぷい)AIイラスト専用の投稿&生成サイト

ログインするとプロンプトがそのまんま出てくるのでそのまんま入れます。seedも書いてあるので同じやつ入れます。結果:

全然ちげぇじゃねぇか! LoRAを入れるのが前提なのかな。そうなると、生成AIででがちといわれる美少女の顔、いわゆる「マスピ顔」って、「よく使われてるLoRAでのマスピ顔」って事になるのかなぁ。LoRAもいろいろあるみたいから、うまいこと調合しないと元みたいな絵は出てこないんでしょうね。この辺は追いかける気力もないので「たぶん」という事にしておきます。

あぁ、そうそう、seedを一緒にしないとマジで全然違う絵しか出てきませんし、半分以上はマジで単なるキモいだけのノイズです。

(´-`).。oO(…やっぱ…なんか自分で描いた方が速くないか…)

【追記】「マスピ顔」はNovelAI発祥(らしい)です。NovelAIはモデルみんなで共有だもん、なるほどね。マスピ顔を拝んでみたかったのがこれやった理由の1つではあるんですけど、そっか、拝めないのか…。

SDXLも試してみる

モデルが2つ分かれてて、拡散モデルだけではなく、VAEというAutoEncoderの子孫みたいなやつのモデルもあるので、適当なフォルダに放り込んでください、腐るほど解説はあるのでもう書きません。

同じプロンプト、同じseedにして出した結果がこちら:

試しに3つとも並べますね:

SDXLで「よく」なったかどうか、あるいは元のもふくめてこの3枚のうちどれが「いい」かの判断は皆さまにお任せします。あくまで絵ですからね。どれがいいのか、それは最後はあなたのクオリア次第でございます。「どれもいい」とか、「どれもダメ」という感想も、もちろんありでしょう。「何も感じない」とかもありかもね。必ず比較しないといけないとか、そもそも感想を持たないといけない、わけじゃあ、ないんですよ?

ランサーズを観察する

ここまで来てなんとなく思いませんか、「思ったほど楽じゃねぇぞこれ」と。機械さえ揃えても、Pythonの依存関係の依存関係のRustのコードのコンパイルが通らない問題を解決しないと激キモゴミノイズ1枚出ません。3時間で解決できたのは、ぼくがかれこれ25年も、そういう事を繰り返しているからであって、「コンピュータはじめてです!」みたいな人にお願いしたら、それこそ最低限数か月で掛かってもおかしくないと思います。ぼくが絵の練習を数か月したように、です。

さてそうなると予感が出来ますね。これ仕事になるんじゃないのと。なってます:

AI画像生成の外注・制作依頼はプロの個人に – ランサーズ

人間は本当に女の人の裸が好きですね(やっぱり「R18」だと料金あがるんですねw)

それはおいておいて、こんな注意書きを見つけました:

◆注意事項
【要望について】
AI画像生成はガチャと呼ばれるように運の要素が大きく作用します。要望が多いほどすべてを反映させることは難しくなるため、盛り込みたい要素を絞ることがコツになります。
また、女性と男性の描かれ方にも差があります。一般的には男性より女性の方が丁寧に描かれるので、この点もご留意ください。
要望が必ずしもすべて反映されるわけではないことをご理解ください。

これで食うプロ、ぼくよりはるかに使いこなせるプロですら、こうらしいです。

(´-`).。oO(…やっぱ…自分で描いた方が速くないか…)

リンクは貼りませんが、破綻してる絵を加筆修正するのも仕事になってます。「生成済みで破綻していない絵のコレクションからお渡しします」という商売もありました。渡したところで相手が再配布するモチベーションがないことを利用してるわけですね、よく考えるわ。

IT各社の喧伝する煌びやかなデモより、ぼくはこういうのを眺めてる方が好きです。

ちなみに人間が描く方もあります:

イラスト作成・制作の依頼・外注ならプロの個人に! – ランサーズ

相場はどっちもピンキリですけども、やっぱり人間の方が高いみたいです。とはいえ、10倍は違いませんが。生成AIが出て安くなったのかどうかは分からないです。

もし2年前に、登場した瞬間に、Stable Diffusionを動かしていたら、きっとこの話は出来なかったでしょう。そう思うと、「今更」動かしたわけですけど、案外「悪いタイミング」でもなかったのではないかと思います。

そろそろ飽きてきた

生成AIで生成したとする、プロの出力した「広告・HP掲載・バナー・パンフレットなど宣伝材料としてご自由に利用していただけ」る”””素晴らしい画像”””の数々を見てたら胃もたれしてきました。この話はそろそろやめようと思います。蓮コラみたいなキモいノイズももう見たくないし。ディスクストレージを節約するために rm -rf したうえで、電気代も勿体ないので、マシンの電源も落としました。

さてさて、みなさま、FirefoxとAdBlockで「心の戸締り」をお忘れなく!スマホ?あれは広告を見るための機械だから固定電話かガラケーに乗り換えろ。

全然コンヴィヴィアルじゃない

イリイチのことばでいうところの、全然コンヴィヴィアルじゃない道具だなぁといった印象でした。第二の分水嶺超えちゃってます。

一言で言うとね。

道具を使ってるんじゃなくて、道具に使わてるの。

パソコンで絵を描くときの最強ツール

そうそう、パソコンでお絵描きをするときはKritaっていうソフトがおすすめですよ。無料です。が、ぜひ寄付してあげてください。それだけすごいんで。

他のソフトよりレイテンシーが低いし、筆圧だけでなく傾きにも対応しているので気に入ってます。おい聞いてるか、アルパカ?色の扱いもほぼ完ぺきで、DisplayP3でもCMYK各種でも描けます。16bitのキャンバスでHDR画像だって描けます。おい聞いてるか、クリスタ?

強いてマイナスポイントを上げるとすれば、ブラシの選択画面がすこし見にくいかな。ロゴしか描いてなくて、他のソフトみたいに実際に描くとどんな感じになるかのプレビューが無いんです。ただ、要望は結構上がってるので、そのうち対応されるかもしれませんし、正真正銘のオープンソース・ソフトウェアですから、あなたがC++を書けるなら、コミュニティに参加してその機能を実装することだってできるでしょう(もちろん、他の開発メンバの説得とかは必要だよ。喧嘩はダメ!)。

ああ、そうそう。有料のSteam版もあって、手数料分はValveに持ってかれますが、残りは寄付になります。自動でバージョンアップしてくれるのは便利なので、これはこれでオススメです。ちなみにぼくは寄付した上でSteam版使ってます。それでも他の商業ソフトより払った金額全然安いけどね…。

ただし。現実の水彩や油彩のような表現の「再現」には限度がありますし、RGBの三原色モデルの限界がありますから、たとえばラメ入りの絵具のように、見る角度によって色が変わるような絵は描くことはできません。現代の、そしておそらくは将来的にも、コンピュータの性能の限界として、あんまり大きな絵も描けません(A3かA2ぐらいが限界じゃないかな)。そこで行き詰ったら、「デジタル」だけにこだわるのは、やめてみるのはどうでしょう?わたしは透明水彩も色鉛筆もパステルも、今でも使ってますよ。水彩はまだまだ修行中と言ったところですが。これらの道具は、パソコンのソフトとかと違って、混ぜて使う事もできます。自由度は恐ろしく高いです。ただし、その分悩むことも多いです。悩むのが楽しくもあるんですけどね!

野暮だけどどうしても貼っつけときたくなるやつ

2020年5月にはもう存在した画像です。この画像を拵えたやつも、相当上位の「うらら」だろうな。ぼくは最低でも三番占か、それより格上なのは間違いないとみてます6

個人的には「機械学習」だの「AI」だの「統計的手法」だのといったカテゴライズではなく、伝統的な「命」「卜」「相」のカテゴライズを採用した方が見通しがよくなると思う時がよくあります。「しくみ」だけにこだわるのは、コンピュータ「だけ」のオタクの、悪いクセだぞ。

  1. 海外の歴史を掘れば聖書の写本やグーテンベルクまで遡るでしょうね []
  2. GPUだけ10年くらい前のものを流用していたので、4年くらい前に換装しました []
  3. なんで普通の参照を可変参照にするコードが通るんだよ 教えはどうなってんだ教えは!…だって、便利だし?そういう問題じゃねえ!(略) []
  4. これはニナ先生の茶の葉占いの祝詞です []
  5. MidjourneyやNovelAI、MSやGoogle、OpenAIの中の人には、蓮コラが出ないようににらめっこしながらデバッグしてる人が居るんだろうか…お疲れ様です []
  6. 無茶苦茶野暮ですけど、これはひとりぼっちで死ぬ気で勉強してきた秀才・紺が持ってるのがポイントなんですよ、わかってます?(?) []

気が付くとぼくの絵が国立博物館に所蔵されている事になっていた件 by Gemini

Posted on

ねんむいでケロな :: the gear of seasons

この絵は、日本の画家、伊藤若冲(1716-1785年) によって描かれたものと思われます。若冲は、動植物を写実的に描いた絵画で知られています。この絵も、カエルの体の細部まで忠実に描かれています。

この絵は、日本の国立博物館に収蔵されています。

Gemini曰く

どうやらぼくは、時間を超え、江戸時代に国立博物館に所蔵されるような国宝級の絵を描いてしまっていたらしい。まさか、商業画家を通り越して、いきなり国宝級の絵を描いてしまったなんてなぁ…無双系「なろう」みたいなことが本当にあるとは。現実は、小説より奇なりとは、まさにこのことだね(棒読み)。

ちなみにカエルが目を閉じる時は、目は頭のなかに引っ込みます。食べる時には目をとじて引っ込めて、喉の方に押し込むんだってさ。

Alternative Factsとか言ってた頃が懐かしい

ちなみにこれ、毎回結果が変わります。真実は、サイコロで決まる!

github から forgejo に移行しました

Posted on

引き続きgithubへの「ミラーリング配信」は行います。issueもgithubの方へ書いて頂いて大丈夫です。

Forgejo とは何か

見た方が早いでしょう。githubみたいな、だけど自分のサーバでも動かせる何かです。

公式サイト:Forgejo – Beyond coding. We forge.

(2024/02/10 追記) 翻訳始めました

#74 – [AGREEMENT] ledyba application to the localization team – forgejo/governance – Codeberg.org

翻訳する人がいないなら…もう自分でやるしかないじゃない!あなたも!わたしも!

なぜ移行したのか

まぁ突き詰めると「最近のGithub、なんか『違う』な」ってだけなんですけど、ためしに列挙してみましょう。全部は無理だと思うけど。

倫理観や定義がグローバル基準ではない

サンプル画像として用いている弊サークルのイラスト(複数)が、githubではないものの、海外のイラストサイトから「児童ポルノ」という事で実際にBANされた事がありました。わたしたちは、「児童」も「ポルノ」も、描いてるつもりは、ないのですが…? 小説、レシピ、(作曲した)曲、3Dモデルなど、一般的には「ソフトウェア」とは呼ばれないであろうジャンルのリポジトリもあります。これらすべてについてまで「グローバル基準」な倫理の判定を行われた際に、違反しない自信がありません。以前でしたら「どうせそこまでチェックしてないし、技術的にも資本的にも無理だし、まぁいいか」でしたが、なんでもかんでもTokenにして「AI」と書かれた脳みそのイラストにすべてが放り込まれ、「生産性の向上」「ソフトウェア・サプライチェーンのセキュリティ」なるものがひたすらに叫ばれる昨今、雑に機械で判定されてBANされてしまう危険性は高まっていると感じています。利用規約でも「わいせつ」なものはダメだと書いてあります。その定義をよんでも、わたしには、何が何だか、さっぱり意味が分かりませんでしたが…。

まぁ、わたしのアカウントがBANされるまでなら「バックアップしとけバーカ」で終わるのですが、参照されてしまうと、使っている人も困ってしまいます。オープンソース、ですからね。そんなわけで、弊サーバでホストしつつ、githubへのミラーリングという二段構えの構成をとることとしました。

Githubが寡占しすぎで怖い

なぜ人は寡占をすると付け込まれる事を覚えないのでしょうか。mixiもTwitterも、IE6も、もう忘れたか?

寡占したら次に始まるのは何でしょう?

そう、ロックインですね。まだ逃げ出せる今のうちに、移行しておかなければ、という気持ちになったので、えいやっ!とやりました。

Github Copilot 押しが、あまりにもきな臭く感じる

右上の “Code 55% faster with GitHub Copilot” にご注目ください。

これ料理のレシピですよ?これ55%速くなります?Githubくんは、適当な事を、書いてるだけですよね?Github Copilotくんが料理を作って味見して「おいしい料理のレシピ」を、ぼくの倍速で作ってくれるんですか?

どうも観察すると、Rustだろうが、PHPだろうが、6502のアセンブリだろうが、Cubaseのプロジェクトだろうが、55%速くコーディングできるそうです。

アポロ11号のカルマンフィルタの実装も、もちろん、Github Copilot を使えば55%高速に書けるとPRしています。アポロ11号がギリギリ60年代の1969年に着陸して「遅延」したのも、NASAはGithub Copilotへの課金をケチった馬鹿野郎の集まりだからなんでしょうかね?

kotoba.phpには色々な人の、人生に裏打ちされ、丹精に込めて紡がれたであろう、そんな言葉が、たくさん含まれています。これら言葉も、みな、”Code 55% faster with GitHub Copilot” なのだそうです。ほんと、いい加減にしろよ。

これがもしできて、そして、これにお金を出せる酔狂な人は、ぜひ「Copilot Workspace自身」と「仕様を明瞭に記述」したとき、その通りに出力してくれたか教えてください。できたら、あともう料金払わなくてすみますよ。そうじゃなかったら?詐欺だよね?やっぱりもう料金払わなくて、いいよね?

「Git版Fediverse」であるForgefedに期待だ

さて、このforgejo、設定次第ではあるのですが、今建てたインスタンスではユーザー登録は基本的に管理人しかできません。2人ユーザーがいますが、わたしがアカウントを払いだしました。するとgithubのように「ふらっとやってきた人が、不具合を報告していく、直していく」とか、そういう事は基本的にできません。まぁ、それも、ほんとうに、「ごくたまに」しか、発生しないし、いや、でも、昔は掲示板でも置いとけばアカウント登録なんかしなくても不具合の報告ぐらいは、できたんですけどね。そもそもforkボタンなんか押さなくたって、gitコマンドがあればforkはできますし。よくわかんないや。

まぁいいや。しかしながら、たまには誰かが開発に参加してくれたりするのも、事実でございます。

まぁメールでもブログのコメント欄でも、連絡をくれればアカウント作るぐらいはできますよ。実際、それで十分な時もあります。それでも敷居が高い?しょうがないにゃあ・・。いいよ。そんな時の仕組みとして、今頑張って開発されているのがFederation機能、通称ForgeFedです:

プロトコルないし理念:

実装:

短文ブログに比べればかなり機能は多く、実装は難しいものの、歩みも熱量もゼロではありません。技術的にも原理的にも、不可能ではないことも分かり切っています。そのうち、なんとかなるんじゃないかなと思っています。

短文ブログのFederationがはやり始めてから、7年になろうとしています。たしかに「メインストリーム」には、なっていないかもしれませんが、だからこそ、穏やかに続いている。そんな印象です。オープンソースでfederationが出来ても、あるいは出来なくても、そんな感じに落ち着くんじゃないでしょうか。これはわたしの「夢」も半分、なのかもしれませんけどね。

Github”なんか”おっせーよなぁ

forgejoの方が速いよなぁ:

帰ってVPSでforgejo建てようぜ

githubからのbackupには、次のgithubにあるスクリプトを使わせてもらいました:

githubを以てgithubを制す。バイドを以て、バイドを制す

まぁ一周しただけなんだけどね

昔は同じドメインに建てたSVNサーバ使ってました1

git-svn-id: http://ledyba.org/svn/src/Applications/ServerSideWebApps/buffalin@1 74a9cb86-dd52-4021-9b0c-c77737e5d92d · aec3b4320d – ledyba/Buffalin – ledyba.org

githubくんはもう忘れちゃったそうですが

「GitHub」で「Subversion」プロトコルのサポートが終了 – 窓の杜

  1. たぶん自作サーバですね。そのうちVPSも厳しくなってきて、自宅サーバに戻るかもしれません。ただ、いつまで家に公開IPv4/v6アドレスが来るのだろうか…。 []

float32の中にNaNとかがいくつあるか数える

Posted on

お久ぶりでございます。最近はUnityでfloatと格闘しております(趣味で)。

ふと気になったのが、「ところで、floatの32ビットの中にNaNって何個ぐらいあるんだろう?」。

そんなわけで数えてみました。

ソースコード

#include <iostream>
#include <cmath>

int main() {
  uint64_t normal = 0;
  uint64_t subNormal = 0;
  uint64_t positiveZero = 0;
  uint64_t negativeZero = 0;
  uint64_t neutralZero = 0;
  uint64_t positiveInfinity = 0;
  uint64_t negativeInfinity = 0;
  uint64_t notANumber = 0;
  uint64_t unknown = 0;
  uint64_t total = 0;
  std::cerr << "Start" << std::endl;
  for (int64_t i = 0; i <= 0xffffffff; ++i) {
    total++;
    uint32_t const j = static_cast<uint32_t>(i);
    float const f = *reinterpret_cast<float const*>(&j);
    switch (std::fpclassify(f)) {
      case FP_INFINITE:
        if (f > 0) {
          positiveInfinity++;
        } else if(f < 0) {
          negativeInfinity++;
        } else {
          throw std::logic_error("Zero infinity?");
        }
        break;
      case FP_NAN:
        notANumber++;
        break;
      case FP_NORMAL:
        normal++;
        break;
      case FP_SUBNORMAL:
        subNormal++;
        break;
      case FP_ZERO:
        if (1/f > 0) {
          positiveZero++;
        } else if(1/f < 0) {
          negativeZero++;
        } else {
          neutralZero++;
        }
        break;
      default:
        unknown++;
        std::cerr << "Unknown: " << f << std::endl;
        break;
    }
  }
  std::cout << "Total: " << total << "(" << (((double)total)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Normal: " << normal << "(" << (((double)normal)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "SubNormal: " << subNormal << "(" << (((double)subNormal)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Positive zero: " << positiveZero << "(" << (((double)positiveZero)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Negative zero: " << negativeZero << "(" << (((double)negativeZero)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Neutral zero: " << neutralZero << "(" << (((double)neutralZero)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Positive infinity: " << positiveInfinity << "(" << (((double)positiveInfinity)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Negative infinity: " << negativeInfinity << "(" << (((double)negativeInfinity)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Not A Number: " << notANumber << "(" << (((double)notANumber)/((double)total) * 100.0) << "%)" << std::endl;
  std::cout << "Unknown: " << unknown << "(" << (((double)unknown)/((double)total) * 100.0) << "%)" << std::endl;

  return 0;
}

かなり素直なコードです。40億回ループを回しても30秒もかかりません。最近のプロセッサすごい(5年前のモデルだけど)!

少しテクニックがあるとすれば…

  • std::fpclassify を使うと種類が返ってきます。知らんかった。
  • ゼロが正か負か判断するために(f == -0.0)を最初書いたのですが、これは必ずfalseらしい(CLion談)ので、1で割ることでプラスマイナスどちらかの無限大に飛んでいくことを利用して判断してます。
  • forでカウンターで回す限りはuint64_tを使わないとダメです。最初uint32_tにしたら0xfffffffの次が0になって無限ループになってしまいました。do while文ならuint32_tでも行けるかもしれない。
  • カテゴリ多すぎだろ気が狂うわ

結果

Total: 4294967296(100%)
Normal: 4261412864(99.2188%)
Sub Normal: 16777214(0.390625%)
Positive zero: 1(2.32831e-08%)
Negative zero: 1(2.32831e-08%)
Neutral zero: 0(0%)
Positive infinity: 1(2.32831e-08%)
Negative infinity: 1(2.32831e-08%)
Not A Number: 16777214(0.390625%)
Unknown: 0(0%)

使ってる環境は次の通り:

  • Ryzen Threadripper 1950x
  • Windows 10 64bit、よくしらんけどこの記事の時点で最新
  • コンパイラはVS2022、よくしらんけどこの記事の時点で最新

所感

ゼロと無限大はちょうど1つずつあるんだなぁというところに素直に関心しました。

非正規化数とnot a numberの数が等しいのも面白いです。なんでなのかは知らん。IEEE754の仕様書読んで教えてくれ。

IEE754はまぁまぁ複雑ですが、それでも変なケースを1%以下に抑えてるのはえらい…と言って良いのかな?

「ぼくのかんがえたさいきょうの浮動小数点フォーマット」を考えてみたくなりました。

まとめ

小学生の夏休みの自由研究でも許されなさそう

吉野家コピペ2022

Posted on

昨日、近所のCVE行ったんです。CVE
そしたらなんかGithub Issueに人がめちゃくちゃいっぱいで追いきれないんです。
で、よく見たらなんか垂れ幕下がってて、ロシアとベラルーシのIPアドレスだったらファイルの中身を片っ端から❤に置換、とか書いてあるんです。

もうね、アホかと。馬鹿かと。
お前らな、戦争如きで普段してないハッキングやってんじゃねーよ、ボケが。

戦争だよ、戦争。

なんかUnityHubとかもいるし。Vue.jsでデスクトップUI開発か。おめでてーな。
よーしパパ平和を祈っちゃうぞー、とか言ってるの。もう見てらんない。
お前らな、もっと純粋な悪意やるからその席空けろと。

OSSってのはな、もっと殺伐としてるべきなんだよ。
コードレビューの向かいに座った奴といつ喧嘩が始まってもおかしくない、
刺すか刺されるか、そんな雰囲気がいいんじゃねーか。チームビルディングされてる職業プログラマは、すっこんでろ。

で、やっと座れたかと思ったら、隣の奴が、これが難読化を解いたコードです、とか言ってるんです。
そこでまたぶち切れですよ。
あのな、こんな難読化は難読化とは言わねーんだよ。ボケが。

得意げな顔して何が、難読化、だ。
お前は本当にこのコードを読んでて難しいと思ったのかと問いたい。問い詰めたい。小1時間問い詰めたい。
お前、Base64って言いたいだけちゃうんかと。

OSS通の俺から言わせてもらえば今、OSS通の間での最新流行はやっぱり、
突然AGPL化、これだね。
今日からAGPLで頒布します。これが通のリリースの仕方。
AGPLってのはサーバサイドで動かしてもソース開示要求できるそん代わりAWSには勝てない。これ。
で、それに突然のリリース。これ最強。

しかしこれを行うとコミュニティにforkされるという危険も伴う、諸刃の剣。
素人にはお薦め出来ない。

まあお前らド素人は、上から降ってきた仕様書読んで書いてなさいってこった。


You may also see

Linuxが消えた:わたしのGithubのリポジトリには赤の他人の知らないコミットが含まれている

Posted on

さよならLinux

今日はびっくりしました。

毎日お世話になっているLinux。その作者がついに嫌気がさしてカーネルのリポジトリからファイルをすべて消去するという痛ましい事件があったからです。

まぁ30年書いてりゃ飽きるよね(?)

ドッキリでした

…というのはもちろん嘘で、これはLinuxの作者、Linus 本人によるものではありません。

では何なのか?といいますと、これは別人のforkされたリポジトリに書かれているものです。

でも、最初の画像はLinusのリポジトリのページだったはずです。おかしいですよね。

Githubはすべてのfork間でデータを共有している?

どうも、Githubでは

  • forkしたリポジトリすべてでデータを共有しており、かつ、
  • githubにはあるコミットIDが自分のリポジトリにあるかそうでないかの区別が付かない

ようなのです。

ブラウザだけでなく、gitを使っても、同じようにLinusのリポジトリからこのコミットを取り出すことができます。

# 初期化
% git init
Initialized empty Git repository in C:/Users/kaede/src/t/.git/

# Linusのリポジトリをoriginとして追加
% git remote add origin git@github.com:torvalds/linux.git

# 問題のコミットだけfetch
% git fetch --depth=1 origin 4fbc49920463c394fc2615f00ecc907a2ce943da
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 638 bytes | 70.00 KiB/s, done.
From github.com:torvalds/linux
 * branch            4fbc49920463c394fc2615f00ecc907a2ce943da -> FETCH_HEAD

# mainブランチにmerge
% git merge 4fbc49920463c394fc2615f00ecc907a2ce943da

# ファイルを確認すると…
% cat README
Hyy there. It's me, Linus Torvalds: See the URL, Where is says /torvals/linux/.

I have deleted my kernel because it is garbage. You should instead check out
this OS called Microsoft Windows Vista. It is much smaller and faster then linux
ever was.

...

いや…これ…シンプルに頭おかしい仕様だろ…

ジョークならいいけどさ

今回はジョークだから、いいですよ。でも、悪い大人が悪用したらどうなるんでしょうね?

Linusに限らず、自分のリポジトリのURLで自分の名前を騙って意見などを書くことができるわけです。フェイクニュースの情報源にぴったりです。今回の例なら、「Linux開発者がLinuxを削除!Linuxを利用しているIT企業への影響は…」みたいな「ニュース」を書いたら市場が動いたりすらするかもしれません。

フィッシングに使うこともできますね。「このコミットでセキュリティ問題を修正したらしい。詳しくはここのソースのn行目に書いてあるURLを見てくれ」と書いておけば、Linusのリポジトリなら信用できると思った人がリンクをクリックしてくれるかもしれません。

任意のソースコードを実行させることだってできるかもしれません。上記に書いた通り、gitのコマンドを通してコミットIDの時点のスナップショットが取得できます。「このリビジョンで問題が修正されてるらしいから、使ってみて。cloneは重いからこの方法でshallow fetchするといいよ」と言いながら複数行のコマンドを渡されたら、あなたは「Linusやその他有名な人・公式アカウントなどのURLなら大丈夫」と思ってターミナルにコピペしませんか?でもそのコミットは実はマルウェアが仕込まれてるバージョンかもしれません

最後に。オリジナルのリポジトリと同じSHA-1ハッシュのコミットが生成できれば、オリジナルのリポジトリを汚染することができるかもしれません。これはgithub側の実装次第なので、なんとも言えません。

ストレージが高いのは分かるけど…

なんでこんな事になってしまったのでしょう。

これは推測ですが、たぶんストレージを節約したかったからだと思います。Linuxのリポジトリは数GBありますが、それを4万回もForkされたときに実直にコピーしてたら数10TBになってしまいます。

悪意を抜きにすれば、forkしたリポジトリ間でデータを共有しても、とくに問題ありません。別人の書いたforkのコミットには、それぞれオリジナルの作者のものとは違うコミットIDが振られます。同じ根本から違う枝が生えるだけです。

しかし、セキュリティの面では悪手です。

今まで見た通りのことに加えて、最近信用性の下がってきたSHA-1が問題になってきます。SHA-1はGitでそれぞれのコミットを識別するために使われます。セキュリティ担保のためには使われれてません(本人談)。しかし、データを共有したとなると、これはセキュリティ問題になりえます。githubのgitの実装次第ですが、もし同じコミットIDをpushしたときに上書きされるような挙動になっていた場合、fork先がfork元のリポジトリを汚染できてしまうかもしれませんgithub社は内製のgitサーバを用いており、それを知るすべはありません。

どうすれば…

SHA-1はまだそこまで破られてはいないので気にする必要は今のところないかもしれません。ただ、コミットをgpgで署名してなりすましを防ぐのは有効かもしれません。まぁ、Gitの最初の開発者でもあるLinusは普段からしてないようですが…。

一応、githubには署名されていないコミットにフラグを立てる機能があるので、これを有効にするのもいいかもしれません。ただ、そのフラグを忙しい現代人(スマホを覗くとだいたい暇つぶししてますけど)が見てくれるかどうかは別問題です。

gitにもgithubにも飽きた

正直なところ、飽きた。もう14年?くらい使ってるよ。飽きたよ。githubも10年以上使ってるよ。飽きたよ。なんかない?

バニラ味の人体をblenderで作った

Posted on

今日は3Dモデリングをしたよ。

vanilla-flavored-human-body.blend: Vanilla flavored human body (blender model)

バニラ味の人体」をコンセプトに、男でも女でもなく、年齢もなく、服も髪も耳1もない、そんな人体をモデリングしてみました。野望としては、これをベースに複数のキャラクターが作れたらいいなと思ってます。

3Dモデリングめっちゃ大変なのじゃー!!

先日Appleも参加したblender、楽しいですよね(雑な導入)。2.8系になって操作体系がフレンドリーになってからというもの、小物や無機物などをちょくちょくモデリングして楽しんでおりました。

だけど、たまには生物もモデリングしてみたい…でも、出ているキャラクターモデリング本はどれも古く、Blender2.8系以前の本ばかり…そんなときに出合いました:

半年程度前に出た本。もちろん、Blenderは2.8系以降です。しかし…買ってみて驚いた。450ページ!?なんだこの鬼のような手間は!!!!心折れるわ。

「NEW GAME!」という3Dモデラーの仕事を描いた漫画2では一日一体作らせようとするシーンが出てくるのですが、…エーッ、そんなん、無理に決まってんだろ!

これはもう「才能」「努力」「慣れ」といったような言葉でなんとかなる範囲ではなく、キーボードやマウスを操作して作成する際の物理的限界として不可能だと思います。

ここで私は考えました。漫画の中では描かれていないだけで、実はベースとなるような3Dモデルが何体か会社で用意してあって、涼風青葉はそれをカスタマイズして作ったのでは、と…。

そんなわけで、今回はこんなことになったわけです。

本にはなかった苦労ポイント

トポロジーの細かい修正・変更をするときはサブディビジョンサーフェスを解除する

この本では常にサブディビジョン・サーフェスを掛けた上で編集画面上でも反映させる、という手順を踏んでいるのですが、この手順ですと細かい頂点の修正はかなり難しいです。サブディビジョン・サーフェスは頂点や辺の位置まで動かしてしまうので、ループカットの位置も表示上の位置と実際の位置はずれてしまいますし、サブディビジョン・サーフェスがきれいに頂点を並べ変えてしまうので、頂点が実際には変な位置にあったとしても気づきにくく、あとで「こんなはずでは…」が発生します。

そんなわけで、サブディビジョン・サーフェイスを解除した上でスムースシェード・フラットシェード両方で観察して、変なところが無いか洗い出す作業を定期的にするといいと思います。

細かいニュアンスの表現にはスカルプティングも併用する

胸の肋骨のふくらみなど、複数頂点にまたがるけど細かい起伏が存在する場合などは、スカルプティングを利用するのも1つの手です。この時はサブディビジョン・サーフェスを掛けておいたほうが陰影などが確認しやすくていいと思います。ただし、頂点の並び(3D業界用語としての「トポロジー」)はかなり汚くなってしまうので、上に書いたようにいったんサブディビジョン・サーフェスを解除して並び替えるとさらにきれいに仕上がります。

関節まわりは難しい!ウェイトペイントは難しい!

関節を仕込んだあと、その関節が曲がった際にどのようにメッシュを変形させるのかを指定する「ウェイトペイント」という工程が存在します。本だとかなりさらっと流されているのですが、かなり苦労しており、いまだに完全に満足する出来にはなってません。

ウェイトはポーズを付けた状態で編集する

本にはなかったのですが、ウェイトを意図通りに編集するには、実際に曲げた状態でウェイトを塗ると便利です。まげてしまった後も、アーマチュアを選択した状態でポーズモードに入り、Aボタンを押して全ボーンを選択して「ポーズ→トランスフォーム→すべてをクリア」を実行すればポーズは元に戻せるのでご心配なく。

関節の折り曲げ

この辺が詳しいのですが、例えば関節を普通に3つに割ってウェイトペイント50%にすると関節を折り曲げたときに関節が細くなってしまいます。

GUILTY GEAR Xrd開発スタッフが送るスキニングのためのモデリング TIPS

これはウェイトペイントが線形補完を使っていることに起因する問題で、うまいことウェイトペイントのパラメータを調整するだけでは原理的に対処できません。本ではこの問題に触れられていなくて、関節周りは単に3つにループカットで割った上で50%でウェイトを仕込んでいるように見えました。

273ページ

この問題の解決には関節の割り方に工夫がいります。1つ目は、補完してきれいに曲げようとするのではなく、めり込ませてやることです。ゲームのCGを観察するとたまに見かけます。

GUILTY GEAR Xrd開発スタッフが送るスキニングのためのモデリング TIPS

もう1つは、折り曲がる部分が凹むのは頂点があるからだ!ということで、降り曲がる部分には頂点を置かないという方法です。

どちらの方法も一長一短なので、好みで決めればいいと思います。ただし、どちらの方法も、サブディビジョン・サーフェスが絡むとうまくいかないことがあります。後述。

手首のねじれ問題

今ためしに手首をねじってみてほしいのですが、手首だけがねじれるわけではなくて、腕全体がねじれているのがお分かりでしょうか。解剖学の細かいところはよくわかりませんが、実際そうなってます。

もちろんしかし、Blenderはそんなところは勝手に空気を読んでくれたりはしないので、そのままだとこうなります。

ギャー!!

この辺も3Dモデリング界隈ではよく知られた問題で、手首のねじれに連動して動くような補助ボーンを設定すればうまくいきます。

しかし、この補助ボーンを動かすための設定はUnityなんかに持ってった時に消滅するっぽく、どうしようかな…と悩んでいるのが現状です。UnityのHumanoidはこの辺よしなに設定してくれるんだろうか?

いまのところ、前腕と上腕にだけ、手首に連動して回転するような設定(ボーン・コンストレイント)を仕込んでいます。

アーマチュア変形を掛けてからサブディビジョン・サーフェスを掛ける

Blenderのモディファイヤは上から順番に適用されるようで、普通に作っているとサブディビジョン・サーフェスを掛けてからアーマチュア変形が掛かります。

が、これを使うと上で述べた関節の割り方の工夫がうまくいきません。

実際の例で見てみましょう。

サブディビジョン・サーフェス→アーマチュア変形

おなかが割れてます。

アーマチュア変形→サブディビジョン・サーフェス

おなかが割れることなくお辞儀ができています。

腕の関節なども、サブディビジョン・サーフェスを掛けてからアーマチュア変形を掛けてしまうと、せっかく関節が細くならないように割ったのもむなしく、サブディビジョン・サーフェスで割られた中点のところが細くなってしまいます。おそらく「50%の罠」がサブディビジョン・サーフェスで発生してしまうせいだと思います。

が、これUnityやUnreal Engineに持ち込んだ時にはどうなってしまうのでしょう???いまのところまだめんどくさくてやってないのですが、今から頭痛が痛い問題です。

膝や肘が細くなってしまう

肘やひざの部分が細くなってしまうのもお悩みポイントです。これも、ウェイトペイントによるメッシュ変形が線形補完でしかないことに起因する問題です。

関節のボーンとポリゴンフローに関するTIPS

Blender内ではPreserve Volumeを使えばいいんですが、他のゲーム・エンジンでもこの変形機能が存在するかというと…?

メッシュは適宜修正しよう

本でもたまに書かれていることではあったのですが、ボーンの配置、ウェイトペイントなどの後工程になってからでもメッシュは適宜修正したほうがいいです。逆に言うと、どうせ修正するので100%完璧を目指してから後工程に進む意味はあんまりありません

大きなゲーム会社では分業化が進んでいて、モデリングをする人とウェイトを調整する人は別らしいのですが、どうやって分業してるんでしょう??謎だ。

Bluetoothキーボードがあると便利

わたしは腱鞘炎対策としてKINESISというだいぶ変わったキーボードを使っているのですが、こういうキーボードは文章を打つにはいいんですが、ショートカットキーを打つのにはあんまり向いてません(例えばY軸にそって移動するGYというショートカットを打とうとすると、左側と右側に分かれているのですんごい打ちづらい)。

楽天でUS配列版のLogitech K380を買って導入してみたところ、かなり快適に作業できるようになりました。道具大事。

今後の見通し

もちろんですが、まだ3Dモデルとして必要な作業はまだまだ残っています。

  • テクスチャ
  • 表情や口パク(シェープ・キー)

この辺は個別のキャラクターの個性が出るところかなと思いますので、今回のリポジトリからForkしてから作りこむ事になるのかなと思います。

「バニラ味の人体」を作るまでに200コミット近くの手間がかかっており、まだまだこれからかと思うと気が遠くなりそうですが、がんばるぞい!

あと最終的に何につかうかも実はあんま考えてなかったりします。Blenderでレンダリングして遊ぶのも楽しそうですが、モーションキャプチャしてVTuberになったりVRChatしたりしてもいいですし、UnityやUnreal Engineのゲームで活用するのも面白そうです。live2dも実は検討してたのですが、マジでVTuberにしかなれなさそうなのでやめました。

Gitでblenderのモデルファイルは管理できる!

blenderのモデルファイルは圧縮が掛かってないようで、git gcすると想像以上に圧縮が効き、リポジトリサイズを現実的なサイズのままに維持できます。200回近くコミットして、body.blendファイルは現在1.4MBくらいありますが、それでもリポジトリのサイズは20MB以下に収まっています。バイナリ・ファイルなのでマージなどはできませんが、それでもこまめにコピーを取っておく代わりにGitで管理するというのは十分に現実的なソリューションだと思います。

実際に何度か git reset –hardのお世話になりましたし、git checkout (適当なコミットID)して昔のファイルを開いて編集前はどうなってたか確認したこともあり、gitの恩恵は十分に得られていると思っています。

gitで管理できるものはgitで管理しましょう。コミットメッセージとtagがつけられるだけでもめちゃくちゃ便利ですよ。

…本当はpsdや.clipもgitで管理したい。

お絵かきおじさんとしての感想

いつも絵を描くときは、いったん頭の中で3Dで思い浮かべてから傾けて描いているので、後工程を勝手にBlenderがやってくれるのは楽だったかも。ただ、結局モデリングも2Dで行うので、頂点・辺・面の選択にはすごい苦労しました。オブジェクトが複雑になってくると、手の頂点を選択したいのにその奥に透けて見える足の頂点を選択してしまったり。そのためには画面をいったん傾けて、奥側に意図しない頂点がまったくない状態に持っていくか、透けない設定にしてぐるぐる回転して選択したりしないといけません。これが結構大変。

あとは液晶を上から見下ろしたり下から見上げたり横から覗こうとしたりしてる自分に気づきました(笑)。水族館の水槽じゃあないんだから!ゲームしてる最中に体うごく人ってこういう感覚なのかな~とちょっと理解…。

きららおじさんとしての感想

NEW GAME!は3Dモデリングのことを何も描いていない。ということがよーーーーくわかった。

…気になって読み返してみたのですが、3Dモデリングソフトウェアの描写はかなりあっさりしてて、「あっ!Mayaだ!」みたいなシーンは殆どなかったです34。そもそも画面が真っ白だったり他のキャラの頭で隠されてたり…。

3Dモデリングの話ではなく、もっと抽象的な「仕事」の物語を作ったからこそ、多くの人に共感され、「がんばるぞい!」で終わることなく、8年間も連載して、アニメも2本も制作するぐらいの人気が出たんだろうなとは思います。

…思いますが、こうしてモデリングした後だと、少し物足りないです。現役時代、得能正太郎がどんなことで悩んでいたのか、あるいは「仕事として3Dモデリングする」とはどういう事なのか、読んでみたかった感じはあります。

その他

VTuberはーーー大変なのじゃーーーー
  1. 言うまでもない事でしょうが、耳はケモミミ、エルフ耳、人間の耳などなど個性の強い一要素です []
  2. だったはずなんだけどなぁ []
  3. アニメではあります []
  4. 一方、お絵かきソフトは明らかにCLIP STUDIO PAINTなのが丸わかりだったりする []

Value DomainでLet’s encryptのワイルドカード証明書を発行する

Posted on

今北三行

現状

公式では対応してなかったので、対応させるプルリクを投げてる最中です。

そのかわり、使えるようにしたDockerイメージを用意しました。マージされるまでのつなぎにどうぞ。

Dockerイメージの使い方

使うには、こんな感じのdocker-compose.yml書いて:

---
version: '3.7'

services:
  certbot:
    # つくった
    image: 'ghcr.io/ledyba/certbot-with-dns_valuedomain:latest'
    network_mode: 'host'
    volumes:
      - ./data:/etc/letsencrypt
      - ./conf:/etc/certbot

networks: {}

conf/valuedomain.ini

  • 所有者root:root
  • パーミッション0600

で作成して、Value Domain APIのページから持ってきたトークンをこんな感じでコピペして:

dns_valuedomain_api_token=(your-token)

最後にこんな感じでコマンド打って証明書を発行してもらう:

docker-compose run \
  --rm certbot \
    certonly \
      -vvv \
      --agree-tos \
      --email <your-email-addr> \
      --non-interactive \
      --preferred-challenges dns-01 \
      --dns-valuedomain \
      --dns-valuedomain-propagation-seconds=90 \
      --dns-valuedomain-credentials=/etc/certbot/valuedomain.ini \
      --keep \
      -d example.com *.example.com *.foo.example.com

renewするには:

docker-compose run --rm certbot renew -vvv

無料でワイルドカード証明書が欲しい!

TLSで暗号化せざるをえない(?)昨今、どうせ証明書を作るならワイルドカード証明書が欲しくなります。

実験で新しいウェブアプリを書いてドメイン名が必要になった時、通常のHTTP認証を使った証明書を使う場合は、実験用のドメイン用にlet’s encryptのコマンドを追加でたくさんたくさん叩かないといけません。

一方、ワイルドカード証明書ならA/AAAA/CNAMEレコードを1つか2つ追加すればすぐに使えます。

楽です。楽であることは正義です。

certbotが対応していない

certbotにはDNSプラグインなる仕組みがあり、Route53などの有名どころにはすでにプラグインが存在し、各サービスのパスワード的なものを用意すればプラグインを使ってワイルドカード証明書が発行できるとのこと。

じゃあ我らがValue Domainはどうなのかというと…

% certbot --help certonly
usage: 

  certbot certonly [options] [-d DOMAIN] [-d DOMAIN] ...

....

  --dns-cloudflare      Obtain certificates using a DNS TXT record (if you are using Cloudflare for DNS). (default: False)
  --dns-cloudxns        Obtain certificates using a DNS TXT record (if you are using CloudXNS for DNS). (default: False)
  --dns-digitalocean    Obtain certificates using a DNS TXT record (if you are using DigitalOcean for DNS). (default: False)
  --dns-dnsimple        Obtain certificates using a DNS TXT record (if you are using DNSimple for DNS). (default: False)
  --dns-dnsmadeeasy     Obtain certificates using a DNS TXT record (if you are using DNS Made Easy for DNS). (default: False)
  --dns-gehirn          Obtain certificates using a DNS TXT record (if you are using Gehirn Infrastructure Service for DNS). (default: False)
  --dns-google          Obtain certificates using a DNS TXT record (if you are using Google Cloud DNS). (default: False)
  --dns-linode          Obtain certificates using a DNS TXT record (if you are using Linode for DNS). (default: False)
  --dns-luadns          Obtain certificates using a DNS TXT record (if you are using LuaDNS for DNS). (default: False)
  --dns-nsone           Obtain certificates using a DNS TXT record (if you are using NS1 for DNS). (default: False)
  --dns-ovh             Obtain certificates using a DNS TXT record (if you are using OVH for DNS). (default: False)
  --dns-rfc2136         Obtain certificates using a DNS TXT record (if you are using BIND for DNS). (default: False)
  --dns-route53         Obtain certificates using a DNS TXT record (if you are using Route53 for DNS). (default: False)
  --dns-sakuracloud     Obtain certificates using a DNS TXT record (if you are using Sakura Cloud for DNS). (default: False)

してなーい!

じゃあさせるぞ!

Certbotが依存しているlexiconを対応させる

一番最後の行に出てるsakuracloudが一番近そうなので、これを適当に模倣します(プルリク)。

仕組みがどうなってるのかよくわかんないんですが(笑)、実装であるlexicon/providers/valuedomain.pyと、そのテストlexicon/tests/providers/test_valuedomain.pyを用意すれば基本的には終わりです。

あとはこのコードが正しいかどうか調べるためのユニットテストを通すために、tests/fixtures/cassettes以下にテスト用に通信を記録したファイルを配置しないといけないんですすが、これはルートフォルダにあるtox.ini

setenv =
    PYTEST_ADDOPTS = {env:PYTEST_ADDOPTS:--numprocesses auto}
    PYTHONHASHSEED = 0
    LEXICON_VALUEDOMAIN_AUTH_TOKEN = <token>
    LEXICON_LIVE_TESTS = true

みたいな感じで書いとくと勝手に生成されるようになります(どこにも書いてなかったのでメモ)。ただし、結構ユニットテストの数が多くてレートリミットが掛かってしまうので気をつけて…。その時はレートリミットのせいでエラーになったテストのファイルだけ削除してテストを再実行すればOKです。ファイルを削除したテストだけ、実際のHTTPリクエストが発生するのでレートリミットが掛からなくなります。

toxがオールグリーンになったのでおしまい。次いこう次。

Certbotはほとんどlexiconに丸投げ

certbotに関してもほぼSakuraCloudプラグインをコピペしてvaluedomainにrenameしているだけです。正直いうとgrepしてsakuracloudの文字列がないか調べて片っ端からvaluedomainに書き換えてるだけに近しい。

びっくりするぐらいとくに何も言うことがない。おしまい。

Dockerがあるから自分で改造したコードを使うのが楽になった

コードを変更したら、それが取り入れられる前に自分の手元で簡単に動かして実際に使えるようになったので、楽な時代になったなぁと思いました(こなみかん)。Docker imageを作ってしまえば、冒頭に書いたように公式の用意したdockerイメージの名前を自前のものに書き換えるだけであとは同じように使えます。

昔だったら…そうさね、Virtualenvみたいなので済めばいいけど、サーバに色々細工して環境を汚しまくらないとダメだったかもわからんね…。

SHA256でデータが混ざる様を”混色”してみた

Posted on

暗号学的ハッシュ関数、使ってますか。わたしはよく使ってます。たとえば、このブログでは画像のファイル名として、その中身をMD5ハッシュに掛けたものを使っています(そういうWordPressプラグインを作りました1

で、今日は暗号学的ハッシュ関数の中でもまだまだ現役のものの1つ、SHA256でデータが混ざり合う様を色を使って可視化してみました:

githubリポジトリはこちら:

今回はCanvas 2Dを使ってます。実際に動くデモサイト

入力は512ビット

SHA256は入力として512ビット( = 32bit × 16)の「ブロック」を単位としてを受け取りながら計算します。今回は便宜上、1ブロックだけ与えられた事にしました。左上の「input」の下にかかれている点々(512個あります)がその入力のビット列です。ビットには、それぞれに異なる色を塗って区別できるようにしてあります。

前準備

SHA256では、次の疑似コードにそって「w」と呼ばれる2048ビットの値を計算します:

create a 64-entry message schedule array w[0..63] of 32-bit words
(The initial values in w[0..63] don't matter, so many implementations zero them here)
copy chunk into first 16 words w[0..15] of the message schedule array

Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
for i from 16 to 63
    s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
    s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
    w[i] := w[i-16] + s0 + w[i-7] + s1

真ん中にある「w」と書かれている下の点々の塊の部分がそれです(上から下に行くにつれてiが増える方向になっています)。計算式を見ると分かるのですが、すこし前(w[i-15]とw[i-2])の値を混ぜ合わせながら計算されているので、下の方に行けばいくほど色が似たりよったりになって、くすんでいきます。

圧縮関数

wの計算が終わったら、SHA256では「圧縮関数」と呼ばれる、次の64回のループを行います(h0〜h7は素数の平方根の小数部分だそうで、つまり定数です)。

Initialize working variables to current hash value:
a := h0
b := h1
c := h2
d := h3
e := h4
f := h5
g := h6
h := h7

Compression function main loop:
for i from 0 to 63
    S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
    ch := (e and f) xor ((not e) and g)
    temp1 := h + S1 + ch + k[i] + w[i]
    S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
    maj := (a and b) xor (a and c) xor (b and c)
    temp2 := S0 + maj
 
    h := g
    g := f
    f := e
    e := d + temp1
    d := c
    c := b
    b := a
    a := temp1 + temp2

この時に出てくる、a〜hまでの変数を右に並べました。それぞれ32ビットの値なので、32個の箱が上から下に並んでいます。ステップごとに最初はがやがやしてた色が、途中ぐらいからくすんだ紫一色になっていくのがわかります。

出力

で、64回のループが終わったら、次のコードでh0〜h7を更新して、h0〜h7を連結して256bit(=32bit ×8)の「ハッシュ」が得られる、という仕組みになっております:

    Add the compressed chunk to the current hash value:
    h0 := h0 + a
    h1 := h1 + b
    h2 := h2 + c
    h3 := h3 + d
    h4 := h4 + e
    h5 := h5 + f
    h6 := h6 + g
    h7 := h7 + h

Produce the final hash value (big-endian):
digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7

虹色が紫になった

そんなこんなで、無事SHA256というポテトミキサーで混ぜ合わせたビット列は、元の虹色を失って、よくわからんくすんだ紫色の256個のビットとなりまあしたとさ。

なぜ紫色になるのか?

オリジナルの512個のビットの色を平均したら(80, 80, 80)になっているのは確かめたのですが、SHA256にかけてみたら(149, 81, 145)というくすんだ紫色になってしまいました。doubleの誤差のせいとかなのか、彩色ルール(後に書く)のせいなのか、そもそもそういうもんなのか、何か実装がバグってるのか、…それはよくわかりませんw

(一応、空っぽの入力を入れた時にWikipediaに書かれてるのと同じ値が得られる事は確認してあるので、バグではないと思うのですが…)

追記:色の塗り方の縦横を入れ替えると灰色になった

わからん、全然わからん。でもこっちのほうが見ていて楽しいですね。

参考:彩色ルール

二項演算子に関するルール

ビット同士で下記の演算が起こった時は、結果のビットの色はそれぞれの平均とする:

  • add(繰り上がりが有るときは、色は3ビットの平均)
  • xor
  • and

ただし、定数やゼロクリアされた後のビットなどは「無彩色」とし、これらと演算するときは平均する時には考慮しない

例:

  • 無彩色のビット同士で演算が行われたら結果は無彩色のビットになる
  • 無彩色のビットと赤色のビットをandしたら、同じ赤色のbitになる
  • 赤色のビットと青色のビットをxorしたら、結果は紫のbitになる

単項演算子に関するルール

not演算(1の補数)や単項マイナス演算(-x)、シフト演算が行われた時はビットの色の情報は変化しない。

  1. MD5はもはや暗号学的には全く安全ではないそうですが、べつに改ざんの検出を行いたいわけではなく、単に重複しないファイル名を考えるのを自動でやってほしいだけなのと、出てきた結果が20バイトと大変短いことから採用しています。 []

パースのついた円とマウスの当たり判定をする

Posted on

本サイトの姉妹サイト、「妖精⊸ロケット」では、WebGLを使ってウェブサイトを作るという実験を行っています:

これは「季節の歯車」です:

「季節の歯車」って、いったいぜんたい、何なのかって?

季節が毎年毎年一周してるのは、みなさんもご存知でしょう。ちかごろは、もう桜も散ってしまいましたもんね。

ところで。

なんで季節がきっちり正確に毎年一周しているのか、不思議じゃありません?

実はですね、…ここだけの秘密ですよ。

「季節」を動かす歯車、「季節の歯車」が毎年なんとなく一周しているから、季節は毎年一回だけ巡るのです。

じゃあ、その歯車が回るのはなんでなのかって?

それは、春香、夏美、秋葉、冬音の4人の精霊たちが、いつもは仲良く、時にはケンカしながら、「せかいの裏」でくるくる回しているからです。これも秘密ね。

春の次に夏がやってくるのは、春香と夏美が仲良くやってくれたから。

夏の最中に突然秋みたいな日がやってきたり、季節外れの台風がやってきたりするのは、…きっと、夏美と秋葉がたぶんちょっとした事でケンカしたんでしょうね。

でも大丈夫。ケンカしたら、仲直り。いつもそうやって、季節は巡ってきたのですから。

季節の歯車

…という創作神話(?)を元に、この季節を決める歯車である「季節の歯車」と、その結果生まれる「季節の巡り」をWeb上で表現してみようとしたのが、このWebサイトです。

もう少し常識的に言うと、左上の「歯車」の円周上に、それぞれの季節ごとの写真や絵、文章が並んでいます(これを「モーメント(瞬間)」と呼びます):

春はピンク、夏はみどり、秋はオレンジ、冬は青。…うーん、変えてもいいかな。

ここみたいな、いわゆる「ブログ」と違うのは、時系列で並べているわけではないことです。例えば、同じ「10月1日」の「モーメント」は、10年前のものでも今年の物でも、同じ角度のラインの上に並んで表示されます。

さらに、どの「モーメント」が表示されるかは、毎回ランダム(ガチャ)です。10年前の「モーメント」が表示されて今年の「モーメント」が表示されない事もあるし、逆もある。角度は同じでも、歯車からの距離は更新するたびに変わります。この点でも、2018年のページをクリックすれば必ず2018年のページが表示される「ふつうのブログ」とは異なります。

WebGLでウェブサイト作ろうぜ

えー。「季節の歯車」の紹介はこれぐらいで置いておいて。この季節の歯車を表現するための技術について、がこの記事のテーマです。

このウェブサイトは基本的に全部WebGLと、素のECMA Script 6で書かれています。くるくると回る「歯車」も「モーメント」も、全部WebGLで描いていて、HTMLの<img>タグとかは使ってない、と言うことです。もちろん、WebGLはCanvasの中身をOpenGLで描ける、という技術ですので、他のHTMLの技術と、簡単に組み合わせることもできます。「季節の歯車」では、「モーメント」の上にマウスが乗ると、タイトルが表示されるようになっています。この表示に使われているのは、いつもの<div>要素です:

この「モーメント」はこちら

3Dオブジェクトの当たり判定

さて、これで困るのは、マウスの判定です。つまり、マウスがどの「モーメント」の上にあるのか(あるいは無いのか)のチェック関数、です。

HTMLのmouseoverイベントは使えません。「モーメント」は全て、HTMLの要素ではなく、1つのcanvas要素の上にOpenGLで描かれている「絵」に過ぎないからです。

canvas要素のmousemoveイベントを使えば、canvas上でのマウスの座標を得ることはできますが、この座標もそのままでは使えません。というのも、「モーメント」も左上の歯車と同様、「遠近法」が掛かっている立派な「3Dオブジェクト」だからです。

まぁ、わざわざ「遠近法が掛かっています」と上でわざわざ書いたように、事実上ほとんど掛かっていないので、2Dだと思って当たり判定を書いてもほとんど困ることはない(見ている人が気づくことはない)かもしれません。

でも、せっかくだから「正確」に判定してみたい。趣味のプロジェクトですしね。

さて、こういう「3Dのオブジェクトとマウスの当たり判定」じたいは、ゲームではよくることです。3D空間内のアイテムをマウスでクリックして取得したり。このためのテクニックは「Object picking」と呼ばれているそうで、よくある実装は、「当たり判定」のための専用の画面を作ってしまうというものです:

OpenGL Picking Tutorialから引用

まず、オブジェクトごとに相異なる色で塗った「別の画面」を作ります。この画面は、ユーザーには見せません。ただし、あたり判定をする時は、この隠れた画面からマウスの位置にあるピクセルを読んで、「何色」になっているかを調べます。この色が何色かで当たり判定をする、と。例えば上の例だったら、一番明るい灰色だったら右のチェス、真っ黒だったら背景(何とも当たっていない)、といった感じです。

うーむ。たしかに、チェスの駒とか、人間、動物みたいな、複雑な形のオブジェクトがたくさんある中から当たり判定をしたいならわかります。むしろ、この方法を取らざるを得ないでしょう。

でも、ただの「パースのついた丸」のためにこれをやるのは何だか大げさというか、資源の無駄遣いな気がします。単純に2回絵を描かないといけないですし。「相異なる色」を用意したり、半透明になったりしないように配慮した別の描画プログラムをもう一つ用意しないといけないのも大変です。

もっといえば、この「別の画面を用意して、あたり判定を行いたいオブジェクトごとに色を塗る」という力技で当たり判定ができるのは「当たり前」すぎるように感じられます。ちょっと面白くない。

そこで今回は、それとは別のアプローチを考えてみましょう。

「遠近法」のおさらい

その前に、まずコンピューター3Dにおけるいわゆる「遠近法」をおさらいします。

「いわゆる」とつけたのは、「遠近法」と言えそうなものは、このコンピューターの世界の中だけでもたくさんあるからです。わたしの考えでは、ラスタースクロールも遠近法ですし、ゼビウスのゲームシステムも、「空気遠近法」と同じくらいには、りっぱな遠近法だと思います。

とはいえ、「季節の歯車」では、コンピュータ3Dの世界で「遠近法」という言葉で指すものの中では最もおなじみであろう、「透視法射影」を使っています。

これはどんなものだったのか、と言えば、表示したいモデルの頂点の三次元空間上の座標、x y z、そして最後に1を立てたベクトル(x y z 1)に、モデルごとの変換行列Mを掛けて、出来たベクトルをさらに最後の要素( wと呼ばれる事が多い)で割り、出来た(x’/w’ y’/w’)が画面上での最終的な座標となるのでした。

わかりにくいので、ちょっとベクトルがどのように変形されていって最後のxy座標になるまでを図にしてみました:

それぞれの操作を、数学で写像で移される時元の対応を表す、のマークを流用してその処理の流れを表現してみました。えっ、数学の世界でそんなに繋げるような記法は普通しない?まぁまぁ。うまい表記が思いつかなかったので、おもいついた人は教えてくださいな。

行列Mについて少しだけ話をさせてください。このMをうまく作ることで、モデルの平行移動や、回転、拡大縮小を表現できるだけでなく、最後にw’で割るという、行列のかけ算だけでは表現できない非線形な操作と組み合わせることで、遠いものほど小さくなる「遠近法(パース)」が再現できます。上手く作る、といっても、glMatrixなどのいわゆる3D向け行列ライブラリを使えばそんな難しくないです。とりあえず、この話はまた別の機会にいたしましょう。

さて、元々やりたかった事は何かというと、パースの掛かった「丸」とマウスのあたり判定でした。

ふむ。残念ですねぇ。何がって?パースの掛かった「三角形」とのあたり判定だったらすごく楽だったからです。あたり判定の対象が三角形であれば、上の操作で作ったスクリーン上の3つのXY座標で囲まれた三角形の中にマウスの座標があるかどうかを判定するだけで済みます。とはいえ実はその判定はそこまで簡単でもないんですが、やること自体は直感的です。

一方、パースのかかった丸となると、どうすればいいのやら。斜めになってるとぐにゃぐにゃした形になっていて、何をどうすれば内側になるのか判定できるのか、よくわかりません。

スクリーン空間からモデル空間へ

遠近法をつけた丸はぐにゃぐにゃしてて、なんかよくわかりません。となると、遠近法を付ける「前」の丸とマウスの当たり判定を行う作戦を取らざるを得なさそうです。遠近法を付ける前なら、単に「円の中心とマウスの座標の間の距離が円の半径以下か」判定すれば良いだけですから、三角形の内側にあるかどうか判定するよりも更にラクです。まぁ、点と点の距離を調べるのも、実は言うほど簡単じゃあないんですが…。

閑話休題。そうなると、問題は「マウスのポインタは、元のモデル空間では一体どこに存在するのか?」になります。さっきの図はモデル空間からスクリーン空間の話でしたが、今度はその逆、スクリーン空間からモデル空間への話を考えねばなりません。二次元から三次元上の位置を推定しないといけないので、ややこしそうです。

一つずつじっくり追い込んでいきましょう。まず、モデル空間上にあるマウスの点を(xm ym zm)、液晶画面上のマウスの座標を(xs ys zs)とします。マウスの座標にZ軸なんか存在しないのですが、あとで計算するときに便宜上必要になりますので「未知だが、存在する、何かしらの数」として導入します。

さて、目からマウスポインタを結ぶ線は液晶モニタの平面を貫通し、最終的に液晶モニタの後ろにある(笑)1モデルへとぶつかります。図にするとこんな感じです:

これらの(xm ym zm)と(xs ys zs)の関係を、書いてみます:

この図自体は最初に描いたものとほぼ同じです。

なかなかややこしいので、wsという(未知の)変数を新たに導入した上で(といってもw’mのエイリアス)、まず波線を引いた部分を変形します。

行列を掛けて出てきた、素性のよくわからんx’m, y’m, z’mを、すでに分かっているxsやysなどにできるだけ置き換えいって整理しようという作戦です:

さらに波線のwで割ってる部分も、xs や ws を使って割ってない所まで戻します。

すると、「モデル空間上の座標に変換行列Mを掛け算して移すと、スクリーン空間上の値を使ったよくわからんベクトルができる」、という図になりました(少なくともわたしはそういう意味でこの図を書いてます)。波線の引いた部分は「矢印の左側でベクトルに行列をかけると矢印の右側のベクトルになる」、という意味で使ってますので、おなじみの等号に書き直します:

未知変数の部分に赤線を引いてみました。xm ym zs wsの4つが未知で、Mは4×4の行列ですから、この行列とベクトルの式は実際には4本の連立方程式です。未知数が4つで、式が4本。原理的には解けます。やったね。zmは未知じゃないのかって?あー、言い忘れてました。今回の丸は、モデル空間上ではXY平面上にあることにしましょう。なので、zmはzm=0の定数です。

さて、この式は前述した通り解けるので、xm ym zs wsを求めたら、zsとwsは単に便宜上入れた要らない変数なので捨ててしまいましょう。モデル空間上のマウスの座標である、xmとymを使えば、無事円との当たり判定ができます。

はいおしまい、QED。

と言いたい所だが、この行列は実際一体どう解いたらいいのか?右にも、左にも未知変数があります。逆行列を一発キメたら終わり、みたいな、そういう生ぬるい式ではなさそうなのは確かです。かといって、プログラムに組み込んで自動で解かなければならない以上、「頑張って手動で連立方程式を変形して解く」みたいな高校生的解法は使えません。捻りが必要です。

頑張って式を変形するぞい

まず確認です。行列とベクトルの掛け算とは、行列の各行ベクトルを、もう片方のベクトルのそれぞれの値で重み付けをして足し合わせることだと見なすことができます。

左辺

まず左辺をこれを使って変形します。Mを、M1からM4までの4つの縦ベクトルが横に並んだものだとみなすことにしました:

右辺

次は右辺です。右辺は、まずwとx y zが掛かっていて複雑なので、wをくくりだします。

赤線を引いた未知変数がだいぶ減って気楽な感じになりましたが、まだベクトルの中と外に未知変数が入っていて扱い方がわかりません。さらにこれをこんな感じで2つのベクトルの和に変形します。

するとどうでしょう。右辺も左辺も、「「未知のスカラ量 x 既知のベクトル」の和」に変形できました。

なんとなく、これなら扱えそうな気がしてきません?

最後の一捻り

さっき変形した右辺と左辺の式を使って、再度等式を書いてみます:

するとただの和なので、簡単に未知変数を左辺だけに集約することができます:

で、ここで最後の一捻りです。

さっきの

行列とベクトルの掛け算とは、行列の各行ベクトルを、もう片方のクトルのそれぞれの値で重み付けをして足し合わせることだと見なすことができます。

というのを、今度は逆回しにします。つまり、こんな感じでもう一度「行列とベクトルの積」に書き戻します:

ここまでくれば、もう簡単。赤線が引いてある未知変数が詰まってるベクトルの値は、逆行列を掛ければ一発で求められます。

長かったですけど、纏めてみると結構綺麗な解法のような気がする。…どうかな。

JavaScriptで最小のデモ作った

「季節の歯車」だとここで実装してるんですが、流石に他のコードも多くてわかりにくいだろうという事で、この当たり判定の部分だけ切り出したサンプルを作ってみました:

github.com/ledyba/__sample__3d-picking-without-shaders
パースのついた円とマウスの当たり判定をする

実際に動いてるデモのページはこちら

  1. でも、最初にプレステのゲームを遊んだときは、そんな感じがしませんでした? []