- 投稿日:
Automatic 1111よりいいらしいので使ってみる。
日本語表示が面倒だったので、途中から表示言語を英語に変えている。
確認環境
Env | Ver |
---|---|
ComfyUI | v0.3.38 |
導入方法
インストール
公式サイトからインストーラーをダウンロードして実行するだけ。
Cドライブにしか対応してないらしいが、モデルや出力先は変更可能なので、インストールパスはそのままでよい。
モデルパスの変更方法
- ComfyUIのインストール先を開く
標準はここ:%HOMEPATH%\AppData\Local\Programs\@comfyorgcomfyui-electron\resources\ComfyUI
extra_model_paths.yaml.example
をextra_model_paths.yaml
にリネームする- 以下のコメントアウトをコピペして適当に治す。
is_default: true
のコメントを外して有効化しておく#comfyui: # base_path: path/to/comfyui/ # # You can use is_default to mark that these folders should be listed first, and used as the default dirs for eg downloads # #is_default: true # checkpoints: models/checkpoints/ # clip: models/clip/ # clip_vision: models/clip_vision/ # configs: models/configs/ # controlnet: models/controlnet/ # diffusion_models: | # models/diffusion_models # models/unet # embeddings: models/embeddings/ # loras: models/loras/ # upscale_models: models/upscale_models/ # vae: models/vae/
出力先の変更方法
設定→サーバー設定の一番下にある「出力ディレクトリ」を設定する。
画像の保存ノードのファイル名プレフィックスをクリックし、Valueにフォルダ名/任意の文字列
をつけることでフォルダわけもできる。フォルダ名/
だけ指定してもうまくいかないので注意。
ClipSkipの設定(不明)
CLIP Set Last LayerノードをLoad Checkpointに接続することで実現できるらしい?
Hires.fixの設定
KSampler→Upscale Latent By→KSampler→VAEで繋ぐと同様のことができるらしい。
感想
起動が早い
1111は1分近くかかるがComfyは数秒で起動するため、ここはいいと思った。
保存先を柔軟に変更できる
1111では基本的に生成種別、日付別に保存されるため整理が手間である。
画像の生成品質を上げる方法がわからなかった
これはConmfy UIを以下の構成にして生成したものだ。
一枚目はこういう絵柄だといえばまだありかもしれないが、二枚目は微妙だ。これはどうもHires.fix相当の機能が期待通りに動いていないのが理由に見えるが、恐らくそういった事柄を探求するモチベーションがないと、上手いこと使えないと思われる。
また上記のノード接続だと生成速度も速いとは言えず、これ以上要素を増やすとなると実用性は怪しいと感じた。
現状はまだ1111で十分
1111だとこのくらいのものがパッと出てくるため、個人的には今のところ1111でいいかなと思った。カリカリにチューニングすることで1111を超えてくる可能性は否定できないが、大抵のケースで設定値は固定であり、プログラマブルである必要性はアニメーションとかの分野になってくると思われるので、動画を作るならComfy、そうでなければ1111で十分な気がした。
- 投稿日:
マチアソビで白滝製麺が出していた半田そうめんの雰囲気だけ再現するレシピ。
材料
鳥チャーシューは入手困難で作るのも手間なので、鳴門に繋がるなるとで代用した。
材料 | 分量 |
---|---|
白滝製麵の半田そうめん | 1束 |
いりこそうめんつゆ | 適量 |
なると | 好きなだけ |
すだち | 適量 |
すじ青のり | 適量 |
卵 | 1個 |
水 | 1Lくらい |
調理方法
前準備
ゆで卵を一つ作っておき、すだちと鳴門もあらかじめ切っておく。
そうめん本体
- お鍋に水を入れてお湯を沸かす
- 半田そうめん一束を鍋に入れる
- 6分茹でる
- ざるに上げ冷水でよーく洗う。親の仇と思うくらい洗う。
- 目安としては、麺のぬめりがとれる程度もみ洗いする
- 夏場は水道がぬるくなりがちなので5-6月の時期にやると塩梅がよい
- 器に入れ、具とめんつゆをのせて完成
使った食材の参考写真
白滝製麺の半田そうめん。これは必須アイテムだ。
いりこだしのそうめんつゆは入手難易度が高いかもしれないが、丸天醤油のある兵庫県内では比較的手に入りやすいだろう、たぶん。
すだちは徳島県産しか見たことがないので、容易に徳島感を演出できる良アイテムだ。
すじ青のりはタコ焼き用に常備していたのがたまたま徳島県産だった。四万十か吉野川が多いと思うので、これも割と徳島産は入手しやすいだろう。
アオサは全く別物なので出来れば青のりを入手したいところだ。
マチアソビで出た半田そうめん
雰囲気で作ったので、翌々見なおしてみると、いうほど似てないなと思った。ただ味は似てると思う。
- 投稿日:
前々からこのブログの画像と文字の配置について悩んでいたが、結論が出たのでスタイルを変えることにした。
以前は以下のような方式だったのだが、補足説明と次の画像の説明の境界があいまいで判読しづらかった。
<画像の説明>
<画像>
<補足説明>
今回はこれを以下の形に刷新した。
<画像>
<画像の説明>
<補足説明>
この形式にしたことにより画像を区切り文章ができるため、どちらの画像に対する文章なのかが判別しやすくなった。
何故この形式にしたかは単純で、デイリーポータルZや海の見える駅 〜徒歩0分の景勝地〜など、この書式を採用しているサイトが多いからだ。これらのサイトでは加えて画像タイトルと判るような枠UIもついているが、文章構成が面倒になるので今のところそこまでするつもりはない。一応CSSで画像の上のパディングを広げることで、区切りを判別しやすくはしている。
変更前 | 変更後 |
---|---|
![]() |
![]() |
変化としては上の表の通り。通常の画像は、画像個別にfigure > a > imgとなっており、文章はPタグで囲まれているため、Pタグの後ろの全figureに対しmargin-topを指定して対処している。
div.body-main p~figure {
margin-top: 1em;
}
adiaryの生成するHTMLは画像を挿入したときに前後にPタグを挿入する挙動をするため、手前に文章がなくても妙な空白が生まれてしまうが、現状は許容としている。
このPタグにはMarkdownで書いた画像の前後の行の文字列が入り、brを回避するように実装されているようで、修正が面倒なため、新ブログシステムを開発し、そっちに移行したときに対応したい気がしている。
あああ
<画像>
いいい
例えば、上記であれば以下のHTMLが生成される感じだ。
<p>あああ</p>
<figure><a href="画像パス"><img src="サムネ"></a></figure>
<p>いいい</p>
今回の対応では以下の形式にしているため、前後のPタグの中身は空白になる。要するにゴミが出ている。
<画像>
<画像の説明>
<補足説明>
<画像>
<画像の説明>
<補足説明>
...
今回の対応で対象となった記事は112、変更箇所となる文章行と画像行のセットは約1,089箇所にも及んだため、どこかの記事が置換ミスで壊れている可能性がある。ただまぁ読めなくはないと思う。
このブログはテキストファイルでデータを持っているため、置換作業はVSCodeの一括置換を主に使っていて、一応できる限り目検で怪しいところはチェックしている。たまにメタデータを破壊しそうになっていたり「以下」という文言が含まれていたり、二行連続で画像が続いているなどで整合性が取れなくなっている個所は極力て出直している。
ただどうしても万博記や、しょい地巡礼辺りは画像点数が余りにも多いので文章中に「以下」がないかを機械的に見て、上から下まで流し見した程度にとどまっているため、一部崩れている可能性は否定できない。
ひとまずこの作業をしている中でadiaryのコードをあれこれ見ていたところ、保守性に限界を感じてきたので、adiaryのデータフォーマットと互換性のあるブログシステムをPHP辺りで作りたい機運が高まった。気が向いたら作るかもしれない。
DBはテキストDBだと一括置換がしやすいとかは確かにあるのだが、システム保守やパフォーマンス面ではSQLiteが最強だと思っているので、恐らくテキストDBは捨てる気がする…。
パフォーマンス面についてはウチのように記事数が多いサイトだとSQLiteは1ファイルにデータが収まる関係でファイルI/Oの回数が減る分、オーバーヘッドが減ると考えているためだ。実際adiaryは時として重くなる。WordPressほどではないにせよ、看過していると今後の記事増加に耐えられない気もする。
RDBは今回のような一括置換に対しての保守性は悪いが、総合的なパフォーマンスはいいし、置換に関しては最悪WordPressにあるSearch Replace DBみたいなやつを作れば使い勝手が悪くとも出来なくはないと思うのと、基本的にまず発生しないはずなので考慮しない方向で行きたい。
- 投稿日:
例外設計についての個人的に思っていることを書き出してみる。整理できていないがいったん現状。TypeScriptのケースを意識して考えているが、根幹は例外スローのある言語ではどれも共通だと考えている。
例外とは何か?
本記事で扱う例外とはthrow new Error("ほげほげ");
のように、いわゆるスローされ、try-catchされるものを指して扱う。
例外を多用しない
例外は多用しないことが望ましく、原則として処理が続行不能になる場合を除き、使わないほうが良いと考えている。これはスローされた例外は可視化されづらく、適切にハンドリングされないケースがよくあるからだ。
例外は構造化されたプログラムを破壊する
構造されたプログラムとは順次・反復・分岐の基本構造を階層的に組み合わせたものであり、いわゆる上から下に読めばわかるもの、構造化プログラミングによって作られるものだ。上から下に流れるため非常にわかりやすい。
これに対して存在するのがgoto
を用いたプログラムだ。goto
を使うとコードの色んな場所に前後しながらジャンプすることが可能で、可読性を損ねてしまう。
そして例外は基本的にgoto
のような存在である。例外が起きると例外オブジェクトが投げられ、これはどこに行きつくか予想することが難しい。行きつく先がなければ最悪プログラムがクラッシュする恐れすらある。
例外は処理コストが重い
恐らく大抵の言語において例外をcatchする行為はコストが重い。これはJavaでは特に有名な話だと思うが、Java以外でもそうだと思う。例えばNode.jsでtry-catchで例外を処理するプログラムと、if-elseで処理するプログラムを書き、その実行速度を比較するとif-elseの方が早い。
以下はエラーハンドリングをifで行うプログラムと、try-catchで行うプログラムを作り、100万回走行させたときの処理時間だ。catchに入るケースでは処理速度が低下することが分かる。例外が投げられず、tryの中に納まる限りは低下しない。
処理 | 処理時間(ms) |
---|---|
If正常系 | 4,453 |
If異常系 | 4,204 |
try-catch正常系 | 4,341 |
try-catch異常系 | 7,883 |
これは例外が投げられる場合、最寄りのcatchポイントを探索するのに時間がかかるからではないかと考えている。
Node.js向け検証コード
前述の処理時間を出すのに使ったプログラム
// ==== 実行用共通部品
const execIf = (input) => {
if (input === 1) {
return true;
} else {
return false;
}
};
const execThrow = (input) => {
if (input === 1) {
return true;
} else {
throw new Error('ERR');
}
};
// ==== コールバック処理計測用関数
const getExecFuncElapsed = (cb) => {
const startAt = +new Date();
for (let i = 0; i < 1_000_000; i++) {
cb();
}
return +new Date() - startAt;
};
// ==== If/try-catch検証用、コールバック処理群
const execIfOk = () => {
const ret = execIf(1);
if (ret) {
console.log('OK=');
}
};
const execIfNg = () => {
const ret = execIf(0);
if (ret === false) {
console.log('ERR');
}
};
const execThrowOk = () => {
try {
execThrow(1);
console.log('OK=');
} catch (e) {
console.log('ERR');
}
};
const execThrowNg = () => {
try {
execThrow(0);
console.log('OK=');
} catch (e) {
console.log('ERR');
}
};
// ==== 計測処理
const elapsedIfOk = getExecFuncElapsed(execIfOk);
const elapsedIfNg = getExecFuncElapsed(execIfNg);
const elapsedThrowOk = getExecFuncElapsed(execThrowOk);
const elapsedThrowNg = getExecFuncElapsed(execThrowNg);
// ==== 結果出力
console.table({ elapsedIfOk, elapsedIfNg, elapsedThrowOk, elapsedThrowNg });
いつ例外を使うか?
基本的には大域脱出がしたいケースのみで使うべきだろう。最悪ハンドリングされずとも、基底階層でcatchされれば、それでよいケースで使うのが最も無難だと考える。
大域脱出とは要するにgoto
だ。多重ネストや深い高階関数から浅い階層に一気にすり抜けるときに有効だろう。逆に一階層とか、抜ける階層が浅いレベルでは使わないほうが良い。
例えば処理が続行不能になったケースでは例外をスローし、基底階層でcatchし、エラーログを吐く、クライアントに対してエラーメッセージを返すなどの処理があればよいと考える。
但し例外を使うときは極力カスタム例外を使ったほうがよいと考える。
フレームワークやライブラリの例外をどう扱うか?
例えばバリデーションエラーやHttpClient系の4xx, 5xx系の例外スローはラッパーを作り、例外をエラーオブジェクトに変換するのも一つだと考える。
HTTP GETを行うクライアント関数であれば以下のようなラッパーを作り、正常時は正常レスポンスを返し、異常時でかつ想定内であればエラーオブジェクトを返す、そして想定外の例外であればリスローする、といった処理をすることができる。
const httpGet = (url) => {
try {
return fetch(url);
} catch (e) {
if (e instanceof AbortError) {
return createHttpErrorObj(e);
} else {
throw e;
}
}
}
こうすることで呼び出し元は正常時であればHTTPリクエストをそのままステータスコードに応じて処理し、Abortされた場合はリトライ、完全に予期せぬ内容であれば例外を基底階層まで飛ばして処理を中断するといったこともできる。
リトライに規定回数失敗した場合は、この関数の呼び元でnew OutOfTimesHttpRetryError()
みたいな例外をスローするとよいだろう。
カスタム例外を使う
カスタム例外とは例外クラスを継承した例外クラスだ。
例えばC#ではExceptionのほかに、それを継承したSystemExceptionや、IndexOutOfRangeExceptionなど、様々なカスタム例外が存在する。
LaravelにもAuthorizationExceptionをはじめとし、多様なExceptionが存在する。
これらに限らず、大抵の言語やフレームワークには相応のカスタム例外が用意されているのが一般的で、業務システムやC2のプロダクトでも、例外をスローするケースではカスタム例外を作ることが望ましいと考える。
カスタム例外があると例外種別ごとにフィルタリングすることが可能になり、柔軟にハンドリングしやすく、ロギングの際にも例外種別を記録することで、後々の障害調査でも便利になるため有用だ。
例外を握りつぶさない
例外は時として握りつぶされることがある。そういう必要があるケースも少なからずあるだろう。しかし基本的に例外は握りつぶさないほうがよい。
例外は望ましくない現象が起きているはずで、本質的にハンドリングする必要がある。単に握りつぶしているだけでコメントやテストも書かれていなければ、もし例外が起きたとき、処理が正常に進むのかどうかコードから読み取ることが困難だ。
仮にテストがあったとしてもコードを読むときのコストが増えるので、基本的に握りつぶさないほうがよいだろう。
スローする場合は、例外クラスを用いる
JavaScript系では以下のようなエラーオブジェクトを作るケースもあると思うが、スローする場合は使わないほうが良い。
{
__type: 'HogeError',
message: 'fufagfuga',
payload: someObject
}
スローする場合はErrorクラスを継承したカスタムエラーをスローすべきだ。これはカスタムエラーにはスタックトレースなど、障害調査をするときなどに例外として標準的な情報が格納されているほか、instanceof
でフィルタしやすい、クラスは型情報を持つのでリファクタが容易、error.__type === 'HogeError'
は言語機能の再実装に近く標準的ではないからだ。テストフレームワークでも例外をキャッチするためのアサーションではErrorクラスの継承が必須となっているケースがあるため、TypeScriptでは型検査が上手く通らないケースがある。
- 投稿日:
Open WebUIを使ってローカルLLMとチャットしてみたのでその記録。
確認環境
実行環境はWindows 11。
Env | Ver |
---|---|
ollama | 0.9.0 |
Open WebUI | 0.6.6 |
やり方
Open WebUIをセットアップ済みという前提で進める。
- Ollamaをインストールする
- 使いたいモデルを探す
ollama pull <モデル名>
でモデルを取得する- 物次第だが数~数十GB程度ある
- Open WebUIを起動する
- 管理者設定の接続を開きOllamaをONにする(デフォルトはONのはず)
- 管理者設定のモデルを開き、pullしてきたモデルを有効化する
Ollamaサーバーの起動方法
Ollamaをインストールした直後はOllamaサーバーが勝手に起動するが、それ以降は手動で起動する必要がある。
Windowsの場合スタートメニューから起動できる。Ollamaサーバーが起動していない場合、LLMとして使えないので注意。
所感
Intel Core i7 13700 + GeForce RTX 4070 Ti程度の環境では生成速度の遅さゆえに到底実用に耐えるものではなかった。質問への回答品質もあまりよくなく、実用性は疑問だ。チューニングすれば使えるのかもしれないが、よくわかっていない。
今回試した結果ではRPはGemini以上に破綻するので微妙だった。文章をある程度整理する力はある様に見えるので、用途次第では活路があるのかもしれない。
以下に実行した結果を記録している。
gemma3:27b
恐らくGoogle AI Studioにもいる子。
出力内容
真贋のほどはさておき、中々力の入った文章を出してくる。流石にローカルLLMの中でも注目されているモデルだけある。
しかし出力に3分半程度もかかっており、まったく実用性がない。無料の選択肢という意味ではGeminiやCopilotを使ったほうが遥かによいだろう。
マシン負荷
GPU負荷はないもののCPU負荷が強い。VRAMが足りないとCPUで処理するみたいな情報をチラッと見たのでグラボの性能不足の可能性もある。
lucas2024/mistral-nemo-japanese-instruct-2408:q8_0
CyberAgentが作ったとされているモデルのOllama版?
出力内容
こちらも真贋のほどはさておき、中々いい感じの文章を出してくれる。
生成速度はgemma3:27bよりは早いものの、それでも1分ほどかかっていた。
マシン負荷
CPU負荷はgemma3:27bよりやや低く、GPU負荷が少し上がる傾向があった。
マシン負荷
うちのマシンは200mmファンを四基、CPUにはNoctuaのヒートシンクに120mmファン、リアには140mmファンを装備しているが、gemma3:27bだとこれらがフル回転するので凄まじかった。
StableDiffusionやFF14ベンチ程度ではフル回転することはない。