お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
ジャンル::サイト運営

ここ何年かの間、自分のSNSとかのリンクを集約したり、経歴を書き連ねたりするWebページが増えてきていると思います。例えばHugoを使ったものはモダンで、学生や若い人とかに人気だと思います。流行から結構経っているので、もう廃れてるかもしれませんが…w(Hugoメンテするのだるいと思うし…w

こういう系のサービスは最近だとLinktreeをよく見ますし、リッチでモダンなサービスとしてBentoなんてのも見かけますね。Hugoはセルフホストタイプですが、これらのサービスはホスティングのノウハウや環境構築が不要なのはメリットでしょう。

Bentoは一応私も使ったことがあるのですが、感触がイマイチと言うか、当時はまだプレリリース段階で見た目がモダンなリンク集を作るので精一杯な感じがあったのと、独自ドメインの割当がだるかったので継続利用には至りませんでした。(サービス機能してはなかったのでCNAME当ててCDNなどのリバースプロキシから当ててやる必要があったと思います

かつて私もHugoのAcademicを利用してサイトを作っていたのですが、レイアウトのカスタマイズが面倒なのと、コンテンツをYAMLで書く必要があって書きづらかったり、極めつけはHugoに破壊的変更があった時の対応が果てしなく面倒でメンテが億劫になり、手放した記憶があります。

そしてしばらくはlycolia.infoは使わずにblog.lycolia.infoだけを使っていました。これもさくらのレンタルサーバーからはてなブログに移ったり、note.lycolia.infoとか言うのをGitHub Pagesに生やしたり、消したり、またblog.lycolia.infoをさくらのレンタルサーバーに戻したりと、紆余曲折ありました。

そして月日が経ち、そろそろlycolia.infoも活かしたいなということで今回は頑張らないBioサイトとして作ろうと思い立ちました。まずは重い腰を上げられるように小さく始めて、気が向いたら肉付けしてリッチにしていこうという方針で始めることにしました。どのくらい頑張らないサイトにしたかというと、以下の画像くらい頑張りませんでした。驚くほどシンプル。数分で作れます。何一つ頑張りませんでした。

初期の驚くほどシンプルなサイト

当時のコードがこれですが、わずか24行しかありません。JSもCSSもなく、純粋にプレーンな静的HTMLファイルです。流石にここまでシンプルなのは今時中々ないと思いますね。

<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8'>
  <meta http-equiv='X-UA-Compatible' content='IE=edge'>
  <title>lycolia.info</title>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
  <h1>lycolia.info</h1>
  <ul>
    <li><a rel="me" href="https://blog.lycolia.info">Blog</a></li>
    <li><a rel="me" href="https://github.com/Lycolia">GitHub</a></li>
    <li><a rel="me" href="https://gist.github.com/Lycolia">Gist</a></li>
    <li><a rel="me" href="https://www.last.fm/user/Lycolia">last.fm</a></li>
    <li><a rel="me" href="https://mstdn.hyogo.jp/@lycolia">兵庫丼</a></li>
    <li><a rel="me" href="https://misskey.systems/@Lycolia">みすてむ</a></li>
    <li><a rel="me" href="https://www.npmjs.com/~lycolia">npm</a></li>
    <li><a rel="me" href="https://twitter.com/Lycolia">Twitter</a></li>
    <li><a rel="me" href="https://www.tumblr.com/bonbolium">Tumblr</a></li>
  </ul>
  <p>© 2002 - 2023 Lycolia Rizzim All rights reserved.</p>
</body>
</html>

しかし余りにもシンプルすぎるのでもう少しリッチにしようと18時間後にはこうなりました。最初と比べる結構リッチな感じになったと思います。コードも157行に達し丁度6倍まで膨らみました。長すぎるのでもうここにコードは書けないですw 表示内容は依然としてプレーンな静的HTMLファイルのままではありますが、SSRとかではないので表示は早いと思います。JSはないですが、CSSは入るようになりました。また、懐かしのアクセスカウンターも導入しました。カウント値は過去に設置していたときのものを継承しています。

最初と比べると結構リッチになったサイト、比較で考えるとかなりリッチかもしれない

このサイトはOGを設置したり、A11yに配慮したり、Font Awesome入れたり、Font Awesomeにないブランドロゴはライセンスに配慮しつつ導入したり、そこそこ良い作りになるように意識しています。一旦記憶にある限りの自分のアカウントはリンクしたので、ソーシャルリンクとしては機能するようになったと思います。気が向いたらBiography的なやつも書いていきたいですね。このブログの自己紹介欄すらまともに書けてませんが(

実際に作ってみると色々感じることがありました。例えばそのうちの一つは、かつてはこうやってHTMLを手打ちしてWebページ、いやホームページを作っていたなという懐かしさです。このサイトは初代サイトから移転数を基準で考えると8代目になるのですが、随分遠くに来たものだと思いました。今やHTMLを手打ちするような機会はほぼないです。本業はWeb制作(フロントエンドエンジニア)ですが、仕事でもTSXしか書いてないですし、それすら書かない日のことが多いです。他にもWebArchiveで歴代のサイトを眺めていて、こんな時代があったなとか、昔の自分はこんなちゃんとした文章を書けていたんだなとか、かつてはホームページ運営を通じてこれほどまでにネッ友がいたんだなとか。本当に色々な思いがこみ上げてきました。またあの時代が戻ってきたらいいなとか思うのですが、過ぎ去った時代が戻って来ることはないので、そのあたりは諦めるしかないでしょうね。ただまぁ、こういうので感傷に浸るのも偶には悪くないものです。こないだも浸ってた気がしますが…w

何年も前からHTMLの手打ちは非効率で面倒だとCMSを好んで使っていましたが、偶にはこうやって手でHTMLを書くのもいいものだなとしみじみしました。

また、カウンターを設置する際に久々にPerlのCGIを導入したのですが、久々すぎて意外なところでハマりました。CGIそのものは往年のKENT-WEBさんのものを利用させて頂いているのですが、こちらのPerlコードは改行コードがCRLFなんですね。CRLFで動くのか?と思いながら設置したら謎の500エラーが頻発、パーミッションに原因があるのかと直してみるも収まらず、結果としてレンタルサーバーのエラーログに以下のエラーがあり、改行コードの問題であることが解り、事なきを得ました。

AH01215: suexec policy violation: see suexec log for more details

さくらのレンタルサーバーのエラーログ閲覧画面、管理画面からでなくともSSHからログファイルを見ることもできる

これは昔だとFFFTPとかが勝手にLFに変換していてくれたので起きていなかったようなのですが、今時そんな事する人も多くないと思うのでSSHでアップロードしたり、wgetしたものを直接編集したりしてしまい、発覚が難しいかなと思います。もしまた引っかかることが無いようにGitHubに改行コードをLFにして、ついでに文字コードもSJISからUTF8に変えて更にねこみみカウンターを載せたものを置いておいたので、興味がある人は持っていってください。本家の使用許諾を読む限り多分ライセンス的にはセーフなはず…。

https://github.com/Lycolia/Magick-Nekomimi-Counter/tree/main

しかしカウンタープログラムのソースコードをまともに読むのは今回が初めてでしたが、とてつもなくシンプルな実装で驚きました。まぁ考えてみればCGI叩かれたらカウントアップするだけですもんね…。とは言え、画像を埋め込みHTMLの中に吐き出すのは知識がないと難しいですし、当時としては大変だったと思います。ImageMagickの神がかり的な使いやすさにも驚きました。GDだったらこんなものじゃ済まなかった気がします…w なんか画像の矩形サイズ指定や透過色指定が必要で、汎用的に作ろうとすると面倒だった記憶が…(随分前のことなので記憶があやふやですが…

という訳で長々と語ってしまいましたが、最後に今回作ったBioサイトを紹介して終わりにしたいと思います。サイトというかLPなのでページですが…w

https://lycolia.info/

しかし、フッターにある開設日時の表記が感慨深いです。このブログにも日までは書いてあるのですが、過去に時分まで書いていたことを思い出しWebArchiveからサルベージしてきました。開設当初の記載なので限りなく正確な情報です。秒までは記録がなかったので0秒としておきました。

This site since from 2002-07-03T23:21:00+09:00.
投稿日:
OS::LinuxOS::FreeBSDソフトウェア::zsh

.zshrcbindkeyする時にキーコードが解らず困ったので

確認環境

Env Ver
Ubuntu 22.04.2 LTS
FreeBSD 13.0-RELEASE-p12

確認方法

ターミナルで{Ctrl}+{V}を押下し、次に調べたいキーを押下するとキーコードが見れる

Up/Down/Home/End/Del の設定方法

取り敢えずこれだけ欲しかったので。Deleteは共通のコードみたいです

FreeBSD

## Delete
bindkey '^[[3~' delete-char
## arrow up
bindkey '^[[A' up-line-or-search
## arrow down
bindkey '^[[B' down-line-or-search
## Home
bindkey "^[[H" beginning-of-line
## End
bindkey "^[[F" end-of-line

Ubuntu

## Delete
bindkey '^[[3~' delete-char
## arrow up
bindkey "^[OA" up-line-or-search
## arrow down
bindkey "^[OB" down-line-or-search
## Home
bindkey "^[OH" beginning-of-line
## End
bindkey "^[OF" end-of-line

昨日まで外部モニタ2枚でデュアルモニタが出来ていたのに、今日いきなり出来なくなったが、本体モニタは映っており、外部モニタもどちらか片方だけなら映る状態になっていた。本体モニタは使わないので外部モニタだけ利用したいので、その対処を行った記録。

原因は恐らくWindows Updateなど何かしらの理由でモニタ設定が吹き飛んでいたのだと思う。

前提環境

発生事象

  • 昨日までは本体モニタを削除した状態で外部モニタ2枚でのデュアルディスプレイ環境が動いていた
  • 今日起動すると本体モニタと外部モニタの片方しか映らなくなっていた
    • もう片方は映像信号なし
    • 映ってる方のケーブルを抜くと映らない方に映る
    • この状態で抜いたケーブルを挿すと映っていたほうが消え、挿した方が映る

確認環境

Env Ver
Windows 11 Enterprise 22621.1413

改善しなかった操作

  • 再起動
  • モニタの電源入り切り
  • デバイスマネージャーからIntelのグラフィックドライバを削除
    • Intel(R) Iris(R) Xe Graphics
  • デバイスマネージャーから全モニタを削除

解決手順

  1. デスクトップを右クリックし、ディスプレイ情報を開く
  2. モニタが全て認識されているが映っていないことを確認する
  3. メインモニタを外部モニタに変更
  4. 本体モニタを削除
    1. システム>ディスプレイ>ディスプレイの招待設定>デスクトップからのディスプレイの削除
  5. 外部モニタ2枚に映ればOK
  6. タスクバーとかの設定がリセットされているので直す

あとがき

Dellマシンは何かとトラブルが多いので困るが、法人ユースに特化しているので仕事では使わざるをえないのが難しいところです…。Windowsを選びし者の宿命みたいな感じ。

以前は本体モニタ込みのトリプルモニタが出来ていたのが、無理になっていたので多分そこら辺が何か関係してそうでした。(同時に2枚しか出せなくなっている?)

投稿日:
ソフトウェア::Stable Diffusion技術::AI

最近流行りということもあり、サクッと使い方とか、使ってみた所感を書いてみます。

Stable Diffusion を使うプラットフォームはどこがいいか?

ローカル

ご自宅のマシンです。お金稼ぐなら多分こっち。
ベンチスコアを見る限り最低でもRTX 4070 Tiがあるといいと思います。
勿論、A100があるならそれに越したことはないですが、270万円するのでまず検討外でしょう。

  • メリット
    • 既に環境があれば電気代しか掛かりません
    • 何をしても怒られません
    • 一回セットアップすれば使い回せます
    • ローカルなので細かい融通が利きやすいと思います
  • デメリット
    • RTX 4090を持ってしてもクラウドにパフォーマンスは劣ると思います
    • 環境構築に非常にお金がかかります。グラボ交換だけで考えてもRTX 4070Ti単体で13万ほどするのでAI絵で利益を出せないと厳しいでしょう

クラウド(Google Colab)

  • メリット
    • 取り敢えず試したいというときにお手頃な価格で始められます
      • Colab Proでも1,200円ほど積めば取り敢えず使えます。無料で使うのは微妙
      • 電気代はタダ同然
    • 圧倒的パフォーマンス
      • 512x512の作画であれば1秒程度。ベンチスコアを見る限りRTX 4090でもここまで短くならないはず
      • Golab Proを使った感じだと基本A100が引けました
  • デメリット
    • 長時間使うと金額が膨らみます
      • AIイラストを売って稼ぐには不向きかもしれません
      • ここは軌道に乗ってきたらローカル環境を組むのを考えてもいいかもしれないですね
    • 毎回セットアップが必要になりがちで面倒
      • Google Driveに全部突っ込んでおけば不要ですが、容量問題が…
    • ファイルのアップロードやColab自体の設定変更などの操作がローカルよりやりづらいです(他人のシステムの上にあるので仕方がない)
    • 生成内容によってはBANされる可能性がある
      • 私はされたことがないですが、稀にされるというのは聞きます

モデルについて

あんまり良くわかってないけど主に次の三種類があるっぽい。拡張子のパターンは他にもあるかもしれないけど把握できてないです。

  • モデル
    • 拡張子は.safetensors, .ckpt
    • 絵柄がこれで決まる
    • 格納先
      • /stable-diffusion-webui/models/Stable-diffusion
  • VAE
    • モデルに内包されている絵柄を決定する要素?
    • 拡張子は.vae.pt
    • 格納先
      • /stable-diffusion-webui/VAE/Stable-diffusion
  • LoRA
    • 個人が作成した追加学習モデル
    • 既にあるモデルに絵柄やポーズ、シチュエーションを追加できる?
    • 拡張子は.safetensors
    • 格納先
      • /stable-diffusion-webui/Lora/Stable-diffusion

Google ColabでStable Diffusionを使う方法

以下のファイルをColabに取り込み、後述する使い方の通りにやれば動くはずです。

https://gist.github.com/Lycolia/cb432ad1b1ce083482b5487c131b5d12

使い方

以下はGoogle Colab Proの利用を想定して書いています。1,179円ほど払うと数時間は使えるのでオススメです。

  1. ipynbファイルを落としてGoogle Colabにインポート
  2. 編集>ノートブックの設定からGPUクラスをプレミアムに変更
  3. Setupセクションの## model以下のコメントを参考に好きなモデルを突っ込む
  4. Setupを実行
  5. Launch web UIを実行
  6. コンソールに以下のリンクが出てくるのでアクセスするとWebUIが開く
    1. https://xxxxxxxx.gradio.live

モデルがある場所

この先のリンクには性的表現が含まれる可能性があります。周囲に注意して開いてください。

  • Civitai
    • かなり豊富なモデルがありますが、知財的に問題があるものも少なくないと思われます
  • stablediffusion WebUI モデル一覧
    • 日本語で色々なモデルがまとめられています
  • 7th_anime_v3
    • アニメ系イラストの定番らしいですが使ったことはないです
  • AbyssOrangeMix
    • 見た感じ結構クオリティが高いものを出力できる

トラブルシューティング

カーネルエラーが出る

FATAL: kernel fmha_cutlassF_f16_aligned_64x64_rf_sm80 is for sm80-sm90, but was built for sm75

もし以下のようにxformersをインストールしている箇所があれば消すと直る

!pip install -q https://github.com/camenduru/stable-diffusion-webui-colab/releases/download/0.0.15/xformers-0.0.15+e163309.d20230103-cp38-cp38-linux_x86_64.whl

PyTorch と torchvision のバージョンの整合性があっていないエラーが出る

RuntimeError: Detected that PyTorch and torchvision were compiled with different CUDA versions. PyTorch has CUDA Version=11.7 and torchvision has CUDA Version=11.8. Please reinstall the torchvision that matches your PyTorch install.

web UIを起動する前にバージョン指定でコンポーネントをインストールする

!pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 torchtext==0.14.1 torchaudio==0.13.1 torchdata==0.5.1 --extra-index-url https://download.pytorch.org/whl/cu117

モデルや画面とかいろんなロードが終わらない

30秒以上かかる場合は異常なので画面をリロードすると直ることがある
画面動かない系は基本リロードで直る。多分Colab側の負荷で詰まってる

VAE を設定する方法

  1. Quicksettings listsd_vaeをカンマ区切りで追加
  2. 画面リロード
  3. モデル選択の横にVAEの選択メニューが生えてくる

参考出力作品

プロンプトを深く捏ねてないのでクオリティは微妙ですが、取り敢えずこんなのが出せますというサンプル。
モデルはAbyssOrangeMix3、VAEはkl-f8-anime2を使ってます。

屋敷の森で読書する少女
ジャケットを着たたくあん眉の女性
たくあん眉の女子大生

投稿日:
言語::C#開発::テスト

Windows向けのツールを作ろうというので、昔よく使っていたC#.NETで開発をすることにしたのですが結構苦労があったのでその話を書いていこうと思います。Unit testingを書くのは一旦断念しましたが、暇があれば挑戦したいとは思ってます。

事のいきさつ

WindowsのVSCodeでRemote Development拡張を使うことが多いのですが、リモートエクスプローラーにアイテムが増えてくると移動したいフォルダを探すのが大変になってくるのと、ここに出てないフォルダを開くのが結構手間という問題があり、これを解決できないかということを考えていました。

そこで考えついたのがWSLやSSHのネットワークパス上でExplorerの右クリックメニューを開いたらVSCodeがリモートモードで起動できると良いのでは?という所でした。Windows向けでexeからバイナリ起動するならC#で書くのが楽だろうと考え、C#での開発に着手しました。

疎結合な実装でUnit testingもできたらいいなーと漠然と考えながら開発していたのですが、最後にC#を書いたのは3年ほど前で、C#でモダンな実装をした経験もなかったので結構苦労しました。よく考えたらTypeScriptかJavaScriptくらいでしかまともにやったことがないし、UT自体他言語でもGolangかPHPでしか書いたことがなかったので、C#でこれをやるのは自分の実装技術に対する一種の挑戦みたいなところがありました。結論としてはあっけなく破れたわけですが…。

ツールの要件

  • Explorerの右クリックメニューから起動する
  • 開いたパスに応じてWindowsローカル、SSH、WSLを判定し、適切なモードでVSCodeを起動する
  • パス解決には設定ファイルを用いる
    • Explorerから渡されるパスはリモート環境のパスと差異があるので、そこを解決するためのものです

ツールの設計

やることは設定ファイルを読み込み、コマンドライン引数から値を取得し、それらをいい感じに変換してVSCodeに渡すだけです

大まかなフロー

大まかな動作フロー

実行形式

  • コマンドライン引数
    • this.exe <dir path>
  • 設定ファイル形式
    ```json5
    {
    "CodePath": "VSCodeのexeパス",
    // リモートホスト定義。辞書形式
    "Remote": {
    "リモートホスト名": {
    "ExplorerPrefix": "explorerのパスから除外する文字列",
    "AppendPrefix": "explorerのパスに追加する文字列"
    },
    }
    }
    ```

ツールの実装

まずはTDD的にやろうとしてInterfaceを作成し、Classで実装し、ロジック自体は好調に組み上がっていき、テストもすべて通るようになりました。但し実際にexeを蹴ると動かず、テストは通るが動かないゴミが出来上がっていました。(途中で動作確認をしなかったのか?と思うかもしれませんが、実際は完全に動くものを作ってからテスト可能な形に書き換えるという流れで作っていたのでこうなっています)

動かなかった理由は設定ファイルにJSONを採用していて、デシリアライザにSystem.Text.Json.JsonSerializerを使っていたためです。このデシリアライザは標準ではInterfaceに対してJSONをデシリアライズできません(考えてみれば当然ですが)。しかし、テストをするためにはモックをDIしたいので、Interfaceが必要です。

以下は実際に設定を読み込むために実装したClassですが、メンバが全部Interfaceになっているので、標準の状態ではデシリアライズに失敗します。ならばデシリアライザを自作すればいいという話が出てくるのですが、高々設定ファイルを読み込む処理にそこまで情熱を込めるか…?と言うことになり、諦めました。

public class ConfigBase : IConfigBase {
    private IFileInfo? _CodePath;
    private IDictionary<string, IConfigRemote>? _Remote;

    public IFileInfo CodePath {
        get {
            if (this._CodePath == null) {
                throw new Exception("Config Error: Missing CodePath.");
            } else if (this._CodePath == null) {
                throw new Exception("Config Error: CodePath is empty. Set the code.exe path in this field.");
            } else if (!this._CodePath.Exists) {
                throw new Exception("Config Error: CodePath is Not exists.");
            } else {
                return this._CodePath;
            }
        }
        set { this._CodePath = value; }
    }

    public IDictionary<string, IConfigRemote> Remote {
        get {
            if (this._Remote == null) {
                throw new Exception("Config Error: Missing Remote.");
            } else if (this._Remote.Count == 0) {
                throw new Exception("Config Error: Remote is empty. Set the remote infomation in this field.");
            } else {
                return this._Remote;
            }
        }
        set { this._Remote = value; }
    }
}

そもそもこのツールは「設定ファイルを読み込み、コマンドライン引数から値を取得し、それらをいい感じに変換してVSCodeに渡すだけ」のツールです。たったそれだけのツールに入れる仕組みにしては大げさすぎると感じました。

テストをするためにInterfaceを作ったり、本実装とモック用のClassを作る程度まではまだ容認できるのですが、カスタムデシリアライザを作ると、今度はそれのテストも必要になってきます。どう考えてもしんどい。

因みにこのコード、仮にInterfaceをやめても文字列をFileInfoに組み替えるためのカスタムデシリアライザの実装が必要で結構頭が痛くなります…。多分そこはFile.existsをラップしたクラスをDIしてやるのが無難な気がしますね。

この辺はTypeScriptだとimportの中身をJestで書き換えたら終わりなのであんま考えなくていいのは楽ですが、C#だと厳しいなと感じました。

C#でテストを書いていて思ったこと

クラスベースで実装していくとメソッド単位でのテストがしづらく、テストがコケても原因が把握しづらいというのを一つ課題感として覚えました。TSでなんちゃって関数型開発をしていれば関数のUTを書けば関数の挙動を把握できますが、Classではそうも行きません。

仮に1つのpublic methodが5つのprivate methodを呼び出していて、private methodの裏ではprivate propertyが複雑な依存を持っていたとしたらどうでしょうか?
正直デバッグをかけないとどこで何がコケたか特定できないと思います。そんな実装にするのが悪いといえばそうですが、でもクラスってそういうものじゃないですっけ…?お互いに関連性がなくていいならもうそれ関数で良くないですか?って思いました。

勿論、全部静的メソッドにしてClassそのものは単なるエンティティにするのも選択肢の一つだとは思います。しかしC#でそこまでやるか…?という疑念が個人的にあるのと、処理を繋げたテストをUTとして書く方法がなくなると思います。例えばインスタンスメソッドならモックをDIすることでメソッドが呼ばれた事や、戻り値に対する分岐を確認できますが、静的メソッドでこれをやるのは難しいと思います。

Classの単体テストは関数と状態が密結合したテストになってしまうので、いまいち微妙だなと思ったのが今回思ったことでした。