ソフトウェア開発」カテゴリーアーカイブ

snyk を少し触ってみた

SecurityReportを読んだことで知った、snykというセキュリティプラットフォーム。
無料版もあるようなので、ちょこっと触ってみた

https://snyk.io/

凛々しいドーベルマンがトレードマークです。名前はPatch。

価格体系はこんな感じ。
ちょっと個人で使ってみるのであれば、Freeプランで十分なのではないかと思う。

何をセキュリティチェックやテストの対象とするのかは、結構選ぶことが出来る

基本的にはGithubなどのソース管理ツールを登録し、その中のプロジェクトを選ぶ形になると思う

せっかくなので試しに、過去にチュートリアル的に作って放置されているプロジェクトを対象に含めてみた

Code analysis ではミディアムが6件検知されているけど、問題はpackage.json。
作ってから放置されているので、そりゃ問題があるバージョンが定義されているんだろうな。

選択すると、何が問題かを教えてくれる。そこで「Fix this vulnerability」を選択する

一番下にある「Open a Fix PR」を押すと、自動でPRを作ってくれる。
ちなみに、出来ることと出来ないことはやっぱりあって、下の3つは自動では無理のようだ

expressのバージョンが変わったことがわかる。

無事に、驚異が取り除かれていることがわかります。

PRの作成まで自動でやってくれるのはいいですね。
あまり、この手のツールを使ったことがないので、snykが特別に優れているかどうか。比較という意味ではわかりませんが。。。

今回はCode analysis上は問題なかったですが、コード上での指摘も今度見てみたいですね。

自動検知設定

初回にGithubと関連付けた際に表示が出ていたのですが、snykでのチェックを自動的に走らせることが設定で出来ます

ここではGithubを選択した際の設定を表示しています。

例えば以下のような設定があります

  • 対象とするリポジトリはパブリックのみか、プライベートも含めるか?
  • インポートされたプロジェクトにセキュリティとライセンスの問題がないかどうか
  • 新たな脆弱性や既知の脆弱性を検知した際に自動的にPRを作るか
  • 脆弱性を修正するために、最新のベースイメージを使用するようにDockerfileを更新するPRを作るか

自動的に色々と検知してくれるのはいいのですが、そのたびにテストが走ることを考えると、それなりの規模で開発をされている方ではやはりFreeプランでは心もとないと思います。

最後に

これまで実際にセキュリティ系の製品を触っては来なかったので、なかなか新鮮ですね。
作って終わりというわけではなく、継続して開発していくことを考えると、このあたりの脆弱性を自動的に検知して知らせてくれるというのは心強いものです。

実際に、OSSを使わないなんてことは現実問題難しく、そのOSSが別のOSSを使っていて、更にその先で脆弱性が。。。なんて話はざらにありそうですし、それを「頑張って」で終わらせるのは厳しいものです。

製品全体を考えた際に、どのフェーズでどうやってこれら脆弱性に対する対抗策を整備していくのか。これからはしっかりと考えないといけませんね。

The Merge

日本時間の9/15 PM 3:42 に無事、Ethereumの The Merge が完了しました

そもそもEthereumとは?

当初、私も混同してしまっていたのですが、Ethereumは仮想通貨のEthを指すのではなく、Blockchain上で動作するアプリケーションのプラットフォームのことを指します。

そういう話をすると、クラウドを思い浮かべてしまいますが、現状のクラウドは、あくまでクラウドベンダー。大手で言うところのAmazon提供のAWS。Google提供のGCP。そしてMicrosoftのAzureといったように、企業が提供している、いわゆる中央集権的な仕組みが取られています。

さらに、実サーバーとしてはリージョンだとかゾーンといったように、現実世界の国や地域の影響も受けてしまうというのが現状です。
中国なんてまさにそれ。

Ethereumが目指すところというのは、そういった企業や国・地域の影響から脱却した。真に制限のないプラットフォームの構築となります。

もちろん、プログラムを動作させるには現実世界のコンピュータが必要となりますが、特定のコンピュータに依存することなく、分散実行・検証を行い、情報を保存することで、非常に多くのコンピュータを使った一つの大きなプラットフォームを形成するようなイメージですね。

現状の課題

実行するプログラムのことをスマートコントラクトやdAppsと呼ぶことになりますが、利用者の増加に伴って当たり前の話ですが、処理速度が低下するという問題が発生しています。

また、ブロックチェーン上にブロックを追加する際、いわゆるマイニングという行為が発生し、これが電力需要を圧迫しているという指摘もあります。

それら以外も、スマートコントラクトをEthereum上で動作させるには、その処理量やデータ保存量によって、手数料がかかるのですが、この手数料がその時のEthereumチェーン上が混み合っているかによって大きく変動します。

色々ありますが、要するにこれ以上Ethereum上でスマートコントラクトを動かしたりしていくにはスケーラビリティが足りない状態なわけです。

そして、それを解決するべく様々なロードマップがあるのですが、一つの大きな節目となるのが今回実施された The Merge と呼ばれるアップデートです。

The Merge

一番の大きな変更は、これまでPoW(プルーフオブワーク)と呼ばれていた、いわゆるマイニング行為を行って早くより複雑な計算を行ったら報酬がもらえるという仕組みをやめたことだと考えています。

では、どうやってブロックの承認を行っていくのかというと、PoS(プルーフ・オブ・ステーク)という仕組みに切り替わります。
これは、PoWで膨大な計算を早く行ったものが勝利するというものから、よりEthを多く持っている人からブロックの承認者を選出するという仕組みです。

つまり、ブロックの承認者選出に対して、膨大な電力を必要としない仕組みとなるわけです。

これまで、マイニングを行っていた報酬として配られていたETHも、より多くステーキングした人に対しての報酬へと切り替わるとともに、新規の発行枚数は減る見込みです。

つまり、ETHの流入量が現在と比較すると減っていく形となるため、場合によってはETHの値段は上がるのではないか?と思います。

何はともあれ、今回の The Merge 後、ETHの価格もそうですが、ガス代やスケーラビリティの問題が想定通り解決されるのか?

これから楽しみですね

Cloud Security Report 2022 by snyk

Twitterを物色していたら、こんなものを見かけた

把握していなかったのだけど、セキュリティプラットフォームを提供するsnyk(スニーク)という企業があり、そこが出しているセキュリティレポートということ。
レポートの中身としては、エンジニアやセキュリティの専門家に対してのリサーチを行った結果をまとめたようなものだ

早速ダウンロードして読んでみた。
簡単な登録で読むことが出来るので、興味がある人は手にとっていただければと思う。

クラウドにおけるリスクの代表

開発者目線でクラウドのリスクって何かな?と考えると、やはり情報漏洩だろうな、と思ったらやはりそのあたりだった。

P4. serious cloud security

data breach(データ侵害), data leak(データ漏えい)、Environment intrusion(環境侵入)が多い。
もちろん、クラウドのダウンタイムも34%ということでリスクと言えばリスクだけど結局のところ対応しなければいけないリスクとしてはセキュリティなのだという。

もちろん、これは snyk というセキュリティプラットフォームを提供している企業が出しているレポートなので既定路線ではあるんだろうけど、考えなければ行けない大きなテーマであることには変わりない。

リスクへの対応

本レポートでは、それらセキュリティリスクに対応するためにIaC(infrastructure as code)を大きく取り上げている。

IaCはどちらかというと環境構築においての効率化的な側面のほうが開発者から見た場合には大きい。

初期の環境構築ではIaCで構築はするものの、実際に動かしていく中での追加変更は、クラウドコンソール上で設定変更していくスタイルだ。

レポートでは、それではダメなんだと。
問題への対応に関してもIaCを追従させていき、IaCに対してのチェックを行っていく必要性を掲げている。
そして、それに関しては、組織のポリシーに従った形であるかをチェックできるツールを使って監査・検査できるようにしていく必要があると。
更に、ポリシー自体もちゃんとコードで表すべきだと。

When security policies are expressed solely in human language and exist
in PDF documents, they might as well not exist at all

P.32 ALIGN AND AUTOMATE WITH POLICY AS CODE (PAC) より

思わず笑ってしまったのが上記、「ポリシーが人間の言葉でPDFとしておいてあるだけなんて、言ってしまえばなにもないのと同じじゃないか!」
うん、PDFなんて読まないよね。。。

IaCに関して

インフラの構築はだいぶ、コードによって管理できるようになっているのは間違いない。
クラウドの環境構築においてはもちろんのこと、Dockerやk8sなどのコンテナ環境に関しても基本は定義ベースで構築する形になってきている。

一方で、構築した後に手を加えることもよくあって、それは構築時のコードに反映されているだろうか?に関してはできているとは言えない場面もよくある。

特に、簡易的なクラウド構築に関してはなれないIaCでやるよりもクラウドコンソール上から実施したほうが早い気がするんだよね。

ぶっちゃけてしまうと、両方できなければいけないというのが答えになるんだろう。
ただ、その中でもIaCで環境を構築するということに慣れていき、そこに対してのチェックを行うことが出来るくらい知識が付けば、しばらくご飯は食べていけるのだろうと思った。

家庭菜園向けのアプリを検討

先日紹介した、技術書店で以下の本を購入してしまいました

https://techbookfest.org/product/7Pzm4nWMKg9iAuX9Vz8Cbh?productVariantID=99cwTnd0rHckbcCgQCKRTf

本書を読みながら、紹介されているGlideと言うのはなかなか面白そうだな、と。

もちろん、ローコードツール独特の融通の効かなさみたいなものはあるんだろうけど、サクッと作ってみるという点では面白そう。
とは言っても、何を題材にするのか?ということに関してがやはり問題になるわけなんだけど、色々考えた結果家庭菜園向けのアプリなんて面白いんじゃないだろうか?と思った。

解決したい課題

私自身が、かれこれ10年以上それなりの広さの場所を借りて家庭菜園をやっている。
本格的な農家と、私のような趣味で家庭菜園をしている人との大きな違いは、当たり前だけど常日頃から見ていることなんてできないということだ。

なので、どのタイミングで何をするのか?
また、収穫の目安となる日程はなにか?
というところが、ズボラな私はいつもわからなくなる

ということで、解決したい課題を列挙してみる

  • なんの品種をいつ植えたのかの記録をしておきたい
  • その品種によって、標準的な今後の作業を知りたい
    • 追肥の時期
    • 実が付き始める時期
    • 収穫時期

その野菜なりがどういうタイミングで追肥が必要となるかや、実が付き始めるのか?は、種販売の場合はよく、種袋の裏に書かれていたりする。

実ができてから、収穫が見込まれるまで何日とか。植え付けから何日とかとか。
その情報を、植え付け段階で記録をしておいて、実際に日付が来たら通知が来る。

対象とする野菜に対して、考えなければいけない害虫やその対策なんかもあるといいかもしれない。

スイカとかを育てると、いつが収穫タイミングなのかが本当にわからない。
実ができ始めてから何日みたいな形なので、そういった記録を、苗単位、実単位で記録することができればいいんじゃないだろうか。

場所や天候によって、実際のところの収穫タイミングとかは変わってくるだろうからそういった情報も参考にして補正をかけることができれば面白そうだ

最終的に、そういった情報をいろいろな人が入力してくれることで、なにか面白い分析ができやしないだろうか。

追加妄想機能

とは言っても、初期段階での入力には課題が残る。
まずは、種袋の後ろを。。。と言っても面倒くさいのだ。

これに関しては、商品情報ではあるのでどこかしらにDBなりAPIになっていないかを考えたいところだし、袋裏を写真にとって画像解析から持ってくることができないだろうか。。。

天気のデータに関してはアメダスがあるので、そちらから。
天気や気温からくる生育のズレなんてのは正直、今後の蓄積されていくデータに期待となってしまうだろうなぁ。

あくまで家庭菜園という規模感で考えるのであれば、そこまで大規模なデータは手に入らないだろうけど、そこにはそこなりの面白さもありそうだ。

妄想アーキテクチャ

データの入力口としては、Glideで作ってみる。
Glideで入力したデータは、スプレッドシートへ書かれることになる。

スプレッドシート上のデータに関しては、外部データに関してはGASを用いてAPI叩くなりスクレイピングしてくるなりしたい

さっき書いたような画像解析なんてのも面白そうだ

どこまでを何が担当するのか?などなど、考え出すと色々出てくるなー

こうやって考えるのって結構楽しいですよね

技術書店13を物色

毎年開かれている技術書店13が今年も開催。
オフラインも開かれているようですが、ちょっと足を運ぶには遠いのと予定が合わない&オンラインで十分だろうとオンライン書店を物色しています

技術書典13 オンラインマーケット
https://techbookfest.org/event/tbf13/market

技術書店で出されている本は、基本的にテーマがマニアックなものが多いので、

「そんな着眼点があったのかー!」

と思わずニヤッとしてしまう本を探してしまいます。

今迷っている本をいくつか紹介します

ノーコード・ローコードで作る!QRを使った『じゃがいも収穫管理アプリ』の作り方

https://techbookfest.org/product/7Pzm4nWMKg9iAuX9Vz8Cbh?productVariantID=99cwTnd0rHckbcCgQCKRTf

ちょうど最近さわり始めたGAS、それにノーコードツールであるGlideというものを利用して実現しているらしい。
Glideってのは正直初めて聞いた

Glide(ノーコード)の使い方を徹底解説!無料でアプリを作成しよう!
https://nocodedb.world/archives/1180

無料でアプリが作れる?
と、見てみると、機能制限があって課金で解放ということですね。
スプレッドシートをもとに簡単にアプリが作れたり、豊富なテンプレートを使ってサクッとアプリを作るという点では面白そう。

本書ではQRコードも使っているので、Glideで作ったアプリで農作物の情報を入力。
スプレッドシートに記載されたその情報をQRコードにしてプリントアウト。
検品に利用する。。。ということなのかな?

倉庫で山のように農作物があるような場合だと、いつ収穫したものなのかをそういう形で記録しておくことは、トレーサビリティの観点からもいいのかもしれないな。

AWS Amplifyで作るIoTバックエンド

https://techbookfest.org/product/ph4YMFR31tnMxEnWrba0Wd?productVariantID=sTL00W9EW0fB5V0DnxYJ20

IoTのバックエンドをAWSで考えるのであれば、 AWS IoT 使うんじゃないのかな?と思わなくもない。
ただ、Amplifyはちょっと気になっているサービスではあるので、実際の用途としては見てみたい気もする

しかし、フロントエンドがそれなりにわかる人を対象としているようなので、ぶっちゃけ読んでもわからない可能性が高いかな・・・?

Amazon CloudWatch[本格]入門 ~クラウドネイティブオブザーバビリティストーリー~

https://techbookfest.org/product/uJL2pyLHyk92xYv4P25cJ7?productVariantID=2K5S2wagDLsyFytmk2RG77

以前にこのサークルの本を買ったことがある。
CloudWatchは重要性というものは認識しているものの、自分自身がそこまで大規模なAWS システムに携わっていないということもあってちゃんと身についている気がしない。

逆に言うと、この本を読んだからといって身についた気がするのか?は怪しいんだけど、変に教科書めいたものよりは可能性があるのではないだろうか?と思わなくもない。

うーん、迷う。

Hands-on LINEBOT

https://techbookfest.org/product/3EUnJ5WbexvCDyMgSJS1qb?productVariantID=x9zhcn94SKg2qqHz2yHTga

DynamoDBやLambdaを使った形でのLINE BOT

実際のところ、LINE BOTを作って何に利用するのか?が一番頭を悩ませそうだ。
でも、LINEにしろ、SlackにしろTwitterにしろ、まだBOTを作ったことがない私としては、なにか一つは試してみたいところではある。

と、ここまで来てぐぐってみたら似たようなのが出てきた

試験日まで毎日励ますサーバーレスLINE Botを作ろう(マネジメントコンソール編)
https://blog.usize-tech.com/encourages-serverless-linebot/

こ、これでいいじゃn

でも、AWSを勉強することではなく、LINE APIの方に重点を置くのであれば本書は良いように思える。
そういう意味では、やはり気になる

Fintechで儲かりたい! -発展編-

https://techbookfest.org/product/v8F3n1vdSwBz5FwXyPjV4L?productVariantID=gPchYDCNHcyNvvCDREw2hJ

こちらも、過去に買ったことがあるサークルの出版。
読み物として面白かった。

株取引BOTみたいなものは、それはそれで面白そうではあるんだけど、基本的にインデックス投資をメインで行っている身としてはそれほどの魅力を感じていない面もある。

紹介文にかかれている、「J-Quants API」と言うのはちょっと面白そうだと思ってみてみた

株式分析チュートリアル | 日本取引所グループ
https://japanexchangegroup.github.io/J-Quants-Tutorial/

ちょーーっと、読み進めたり取り組んだりするのにはしっかりとした時間が必要そうだ。。。

と言うか、この分析の先に果たして投資方面で良い未来が待っているのだろうか。。。

結局何を買おうか

色々と見て回ったけれど、なんというか、「これだ!」と即買いするものにまだあえてない。

前回、前々回とかは結構買ったには買ったんだけどな。
今、一番気になるのはLINE BOTかな?

AWSとLINE。両方ともの事例としても使えるし、もしかしたらその先にCloudWatchが待っているかもしれない。
でも、LINE BOTを作ったとしてもそれが果たして日々を潤してくれるのだろうか?ということに関しては正直分からない。
下手をすると、AWSの費用だけが膨らんでいきやしないだろうか?

ちょっとモヤモヤしないわけでもないが、動き出さなければ何もわからないし始まらないのだ。
ちょっとどこかで試してみようかなと思っている

Google Apps Script を Gitub Actions で簡単デプロイ

GASをさわり始めては見たものの、GAS標準で備わっているコードエディタは悪くはないんだけど、せっかくなのでローカルのVSCodeで開発をしてGithubへPush。
Github Actions を利用してデプロイまでやってしまおうかと。

GASのコードエディタだと、弄り倒してもGithubに草生えないし

Claspのインストール周り

claspという、Apps Script をローカル開発するためのコマンドラインツールをインストールします

clasp
https://github.com/google/clasp

インストールは以下のコマンドを叩くだけ

npm install -g @google/clasp

インストール完了後、claspを使ってログインを行います

clasp login

上記コマンドを打つと、Googleへのログイン情報を取得することができます。
Github Actions では、ここで取得する情報を用いて、Apps Script側へDeployすることになります。

その際、Apps Script の API を呼ぶことが出来るように、Apps Script側でAPIを有効にしておきます

GASの設定値を入手する

作成済みのGASのコードを入手するために、claspを使ってプロジェクトをcloneします

clasp clone "スクリプトID

スクリプトIDは対象とするApps Scriptのプロジェクト詳細から確認することができます

単純に、AppsScriptを表示した際に表示されるURLの一部でもあります。「https://script.google.com/d/**ID**/edit?mid=hoge&uiv=fuga」

clone をすることで、下記のファイルが取得されます

appsscript.json
.clasp.json
コード.js
.clasp.json

コード.jsはAppsScriptのエディタで編集していたJavaScriptファイルです。
HTMLファイルなどを追加している場合は同様にcloneされてくるはずです。

appsscript.json には、プロジェクトに関する設定が記載されていて、対象とするApps ScriptをWebアプリとして利用する場合にはこんな記述になっていると思います

{
  "timeZone": "Asia/Tokyo",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "webapp": {
    "executeAs": "USER_DEPLOYING",
    "access": "ANYONE_ANONYMOUS"
  }
}

初回デプロイ時にWebアプリとするのか、APIとするのかなどを選択することになるので、実際にcloneする際には初回デプロイ後のほうがいいかもしれません。

また、.clasp.jsonファイルではディレクトリの指定が可能です。
Github Actions のフォルダなどを作ることを考えると、ソースファイルはsrcフォルダに移動しておいたほうがいいです。

{"scriptId":"XXXX スクリプトID XXXXX","rootDir":"./src"}

必要事項をGithub Secrets へ保存する

clasp login コマンドを実行したことで、ホームディレクトリ配下に.clasprc.jsonファイルができているはずです。
注意しないといけないのは、clasp clone で取得した.clasp.jsonファイルとは別となります。名前が似ていますが。
Windowsであれば、「C:\Users\XXX\.clasprc.json」に保存されている形です

{
    "token": {
        "access_token": "XXXXX",
        "refresh_token": "XXXXX",
        "scope": "https://www.googleapis.c...",
        "token_type": "Bearer",
        "id_token": "XXXXX",
        "expiry_date": 1662717440887
    },
    "oauth2ClientSettings": {
        "clientId": "XXXXX",
        "clientSecret": "XXXXX",
        "redirectUri": "http://localhost"
    },
    "isLocalCreds": false
}

上記の中から、Deployに必要となる下記の値をGithub Secretsへ登録します

  • access_token
  • refresh_token
  • id_token
  • clientId
  • clientSecret

さらに、デプロイを管理メニューで表示されるデプロイIDも登録します

Github Actions用の定義追加

ここまで来たらあと一息。
というわけで、workflowを定義します

name: CD

on:
  push:
    branches:
      - main
  workflow_dispatch:
jobs:
  deploy:
    runs-on: ubuntu-20.04
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Node.js 16.x
        uses: actions/setup-node@v2
        with:
          node-version: '16.x'
      - name: Install Clasp
        run: |
          npm init -y
          npm install clasp -g
      - name: Create claspc.json
        run: |
          echo \{\"token\":\{\"access_token\":\"${{ secrets.ACCESS_TOKEN}}\",\"scope\":\"https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/script.projects https://www.googleapis.com/auth/script.webapp.deploy https://www.googleapis.com/auth/logging.read openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/script.deployments https://www.googleapis.com/auth/service.management https://www.googleapis.com/auth/cloud-platform\",\"token_type\":\"Bearer\",\"id_token\":\"${{ secrets.ID_TOKEN }}\",\"expiry_date\":1620870307822,\"refresh_token\":\"${{ secrets.REFRESH_TOKEN }}\"\},\"oauth2ClientSettings\":\{\"clientId\":\"${{ secrets.CLIENTID }}\",\"clientSecret\":\"${{ secrets.CLIENTSECRET }}\",\"redirectUri\":\"http://localhost\"\},\"isLocalCreds\":false\} > ~/.clasprc.json
      - name: Push
        run: |
          clasp push
      - name: DEPLOY
        run: |
          clasp deploy --deploymentId ${{secrets.PROD_DEPLOYMENT_ID}}

mainブランチに対してのpushで起動するようになっています。

将来的に、デプロイ先を分けられるように、DEPLOYMENT_IDはPRODをつけて定義しています。
上記yamlファイルを

.github/workflows

フォルダに配備します。
最終的なディレクトリ構成としては下記の様に私はしてみました

PROJECT_FOLDER
  └── .github
       └── workflows
              └── cd.yaml
 └── src
       └── .appsscript.json
           コード.js
  .clasp.json
  README.md

これで動いていることを確認できます。

うまくいかなかった時

Github ActionsのFlowが成功したからと言って、実際にAppsScriptがちゃんとデプロイされるとは限らないです。

Run clasp push
  clasp push
  shell: /usr/bin/bash -e {0}
? Manifest file has been updated. Do you want to push and overwrite? (y/N) 

上記の様なログがclasp push 時に発生していました。

原因としては、clasp clone 後にAppsScriptのコンソール上から、AppsScriptを初デプロイした際にWebアプリの選択を行いました。

デプロイ後にclasp clone していれば問題なかったのですが、Webアプリを選択したことで、appsscript.jsonの中身が更新されたのです。

clasp push 時にその差分が検知されてしまい、上書きするのかどうかを問われて、返答なしでそのまま終わってしまったのですね。。。

現状の不満

なんとか目論見通り、ローカルでの開発とPushすることでのDeployまで持っていくことができました。

一方で、ローカルで作ったものを動かすことができていません。。。
そのため、毎回デプロイして本番確認。デプロイして本番確認を行っています。。。

Githubに無駄に草がわんさか生えることになっているんだけど、実際のところ、ただのタイプミスだったりすることも多くて、少し悲しい。
できれば、動作確認してからcommitしたい。。

というのも、フロントエンドが不得手な私はサンプルを探してきて使ってみているんですが、なかなかこれがうまく動かない。
そして、恐ろしくエラーの原因調査・デバッグが難しい。。。

Vue.jsで書かれたサンプルを改造しようとしていますが、正直心が折れそうで、見た目とか気にせずにものすごく単純なHTMLにしてしまおうか迷っているところです。
とは言え、なんかこのまま引き下がるのも悔しいんですよね~。

というわけで、Vue.jsに関して少し勉強してみようかな・・・?

参考

Google Apps Script (GAS) をさわり始めた

ちょっとしたきっかけで、妻から「こんなの作れたりする?」として見せられたサイトがGASでできていた。

GAS。。。一時期結構話題に登ることはあって、結構便利という話ではあったんだけど、結局のところ必要となる場面もなかったので触ったことないんだよな、ということで簡単に調べてみた。

GASの用途

Googleサービスと連携させることが比較的ラクなので、データを保存する場所としては基本的にはSpredsheetもしくはDriveへの保存になると思う。

軽く検索してみた限りでは、GASの利用用途としては

  • 簡易的なWeb API
  • スクレイピングしてSpredSheetへ保存
  • 簡易Webアプリ

みたいなところだろうか。
スクリプトを走らせることが出来る以上、やろうと思えばある程度のことはできそうだけど、あまり凝ったことをしようとすると、できなくはないが面倒なことになるかもしれない。

確か、以前LINE公式アカウントに関して調べた際も、GASで作ったAPIを呼び出すような例もあった気がする。
それを考えると、API設計なんかを含めて考えて作ることができれば、スピードとかを気にしなければ用途の幅は広がりそうだ

簡易Webアプリ

今回、できないか?と言われたのはWebアプリに分類されるもの。
端的に言えば、スプレッドシートの情報を公開するのと、その情報を使って計算し、結果を表示させるようなものだ。

それだけであれば、すぐにできそう

基本的なGASで作るWebアプリのコンセプトとしては簡易的なもので、ページとしてもHTML一つ。
色々と調べてみるとReactやVueなどでつくってWebpackなどでまとめることでGAS上で動かすことも出来るようだが、あまり凝ったことを今回やってもなぁ、と思ってしまう。

今回のオーダーとしては、最終的には妻の職場で使ってみたいということなので、ある程度自分たちでメンテナンスができないといけないのだ。

というわけで、簡単なWebのフォームを使った計算結果の表示と、データ入力。
また、スプレッドシートの表示みたいなことができればいいのかな?と思っている。

実際のところ、もう少しやりたい事を聞いてまとめて、最終的な完成形というか、業務フローというか。そういったものを考えた上でアプリをどう使っていくのかの動線を考えたいところ。

ReactにしろVueにしろ、凝ったことは出来るんだろうけど、そもそも自分がその領域に関して明るくないわけだし、今回の要求からはオーバースペックなわけだ。
まずは、簡単なところで試してみつつ、これまで手でやっていた自分の作業をGASを使って、より良い方向に向かわせることができれば面白いかな、と思っている。

続・画像生成AIを触ってみた

Docker Composeが途中で止まってしまった原因は不明だが、まずは動かしてみたいというところでDevContainer使ってVSCode上のターミナルから試行錯誤してみようとと。

参考はこちら
Stable Diffusionをローカルマシンで実行する(VSCodeとDevcontainerを使用)
https://zenn.dev/hayatok/articles/6141a9a46e4f48

DevContainer準備

VSCodeで適当なフォルダを開き、Dockerfileを作成します

FROM nvcr.io/nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04

ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo

RUN apt-get update && apt-get install -y wget git git-lfs libglib2.0-0 libsm6 libxrender1 libxext-dev

RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh && \
    sh Miniconda3-latest-Linux-x86_64.sh -b -p /opt/miniconda3 && \
    rm -r Miniconda3-latest-Linux-x86_64.sh

ENV PATH /opt/miniconda3/bin:$PATH

RUN git clone https://github.com/CompVis/stable-diffusion && \
    cd stable-diffusion && \
    conda init bash && \
    conda env create -f environment.yaml && \
    echo "conda activate ldm" >> ~/.bashrc

VSCode のコマンドパレットから「Remote-Containers: Add Development Container Configuration Files…」を選択し、作成したDockerfileを指定します。

devcontainer.jsonが作成されるので、編集します

// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.0/containers/docker-existing-dockerfile
{
	"name": "Existing Dockerfile",

	// Sets the run context to one level up instead of the .devcontainer folder.
	"context": "..",

	// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
	"dockerFile": "../Dockerfile",

	// 追記ここから。GPU利用可のコンテナ起動オプション
	"runArgs":[
		"--gpus",
		"all"
	],
	// 追記ここまで。
	"customizations": {
		"vscode": {
			"extensions": [
				"ms-python.python"
			]
		}
	}

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [],

	// Uncomment the next line to run commands after the container is created - for example installing curl.
	// "postCreateCommand": "apt-get update && apt-get install -y curl",

	// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
	// "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],

	// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
	// "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ],

	// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
	// "remoteUser": "vscode"
}

コマンドパレットから「Remote-Containers: Rebuild and Reopen in Container」を選択することで、コンテナ内でVSCodeが起動する形となります。
VSCode の左下がこの状態ですね

Modelの配置

前回取得した Hugging Face のモデルを、Stable Diffusionがモデルのデフォルトパスとして指定している”models/ldm/stable-diffusion-v1/model.ckpt”に配備します。
このあたりは、”txt2image.py”を読んでいくとなんのパラメータ指定が出来るのかがわ借ります。
別のパスを指定する場合は —ckpt オプションで指定可能となっています

実行!

参考にさせていただいたページに従って、test.pyを用意し、実行します

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/stable-diffusion# python test.py
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    pipe = StableDiffusionPipeline.from_pretrained(
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/diffusers/pipeline_utils.py", line 154, in from_pretrained
    cached_folder = snapshot_download(
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/huggingface_hub/utils/_deprecation.py", line 93, in inner_f
    return f(*args, **kwargs)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/huggingface_hub/_snapshot_download.py", line 168, in snapshot_download
    repo_info = _api.repo_info(
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/huggingface_hub/hf_api.py", line 1454, in repo_info
    return self.model_info(
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/huggingface_hub/hf_api.py", line 1276, in model_info
    _raise_for_status(r)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/huggingface_hub/utils/_errors.py", line 169, in _raise_for_status
    raise e
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/huggingface_hub/utils/_errors.py", line 131, in _raise_for_status
    response.raise_for_status()
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/requests/models.py", line 1021, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://huggingface.co/api/models/CompVis/stable-diffusion-v1-4/revision/fp16 (Request ID: PQ6M8N2Lators-j6XdN6V)

Access to model CompVis/stable-diffusion-v1-4 is restricted and you are not in the authorized list. Visit https://huggingface.co/CompVis/stable-diffusion-v1-4 to ask for access.
(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/stable-diffusion# python test.py
Downloading: 100%|████████████████████████████████████████████████████| 1.34k/1.34k [00:00<00:00, 1.13MB/s]
Downloading: 100%|████████████████████████████████████████████████████| 12.5k/12.5k [00:00<00:00, 11.2MB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 342/342 [00:00<00:00, 337kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 543/543 [00:00<00:00, 557kB/s]
Downloading: 100%|████████████████████████████████████████████████████| 4.63k/4.63k [00:00<00:00, 4.02MB/s]
Downloading: 100%|██████████████████████████████████████████████████████| 608M/608M [00:20<00:00, 29.6MB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 209/209 [00:00<00:00, 208kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 209/209 [00:00<00:00, 185kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 572/572 [00:00<00:00, 545kB/s]
Downloading: 100%|██████████████████████████████████████████████████████| 246M/246M [00:08<00:00, 29.6MB/s]
Downloading: 100%|███████████████████████████████████████████████████████| 525k/525k [00:00<00:00, 583kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 472/472 [00:00<00:00, 476kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 788/788 [00:00<00:00, 864kB/s]
Downloading: 100%|█████████████████████████████████████████████████████| 1.06M/1.06M [00:01<00:00, 936kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 772/772 [00:00<00:00, 780kB/s]
Downloading: 100%|████████████████████████████████████████████████████| 1.72G/1.72G [00:54<00:00, 31.7MB/s]
Downloading: 100%|█████████████████████████████████████████████████████| 71.2k/71.2k [00:00<00:00, 188kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████| 550/550 [00:00<00:00, 532kB/s]
Downloading: 100%|██████████████████████████████████████████████████████| 167M/167M [00:05<00:00, 28.5MB/s]
0it [00:01, ?it/s]
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    image = pipe(prompt)["sample"][0]  
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/autograd/grad_mode.py", line 27, in decorate_context
    return func(*args, **kwargs)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion.py", line 137, in __call__
    noise_pred = self.unet(latent_model_input, t, encoder_hidden_states=text_embeddings)["sample"]
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1110, in _call_impl
    return forward_call(*input, **kwargs)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/diffusers/models/unet_2d_condition.py", line 150, in forward
    sample, res_samples = downsample_block(
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1110, in _call_impl
    return forward_call(*input, **kwargs)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/diffusers/models/unet_blocks.py", line 505, in forward
    hidden_states = attn(hidden_states, context=encoder_hidden_states)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1110, in _call_impl
    return forward_call(*input, **kwargs)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/diffusers/models/attention.py", line 168, in forward
    x = block(x, context=context)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1110, in _call_impl
    return forward_call(*input, **kwargs)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/diffusers/models/attention.py", line 196, in forward
    x = self.attn1(self.norm1(x)) + x
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1110, in _call_impl
    return forward_call(*input, **kwargs)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/diffusers/models/attention.py", line 245, in forward
    sim = torch.einsum("b i d, b j d -> b i j", q, k) * self.scale
RuntimeError: CUDA out of memory. Tried to allocate 512.00 MiB (GPU 0; 4.00 GiB total capacity; 3.13 GiB already allocated; 0 bytes free; 3.13 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

エラーになってしまった。要するにメモリが足りないんだと。
そこでメモリの状態を調べるコマンドを打ってみる

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/stable-diffusion# nvidia-smi
Tue Sep  6 14:52:34 2022       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 515.65.01    Driver Version: 516.94       CUDA Version: 11.7     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:01:00.0 Off |                  N/A |
| N/A   56C    P3    13W /  N/A |      0MiB /  4096MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

むぅ。そもそもいくつあればOKなのかがいまいちわからん。
エラーメッセージに出てきた「PYTORCH_CUDA_ALLOC_CONF」あたりを見ていくと何とかパラメータ指定でうまく行けないかな?という気もするけど、多くの人がStable Diffusionをそのまま使うのではなく、メモリ消費を抑えたバージョンを使っているという事を見聞きしているので、そちらを使うことにする

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2# mkdir basujindal
(ldm) root@21feb17171f4:/workspaces/StableDiffusion2# ls
Dockerfile  basujindal  stable-diffusion
(ldm) root@21feb17171f4:/workspaces/StableDiffusion2# cd basujindal/
(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal# git clone https://github.com/basujindal/stable-diffusion.git

適当なフォルダを作って、リポジトリからclone

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal# cd stable-diffusion/
(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# python optimizedSD/optimized_txt2img.py --prompt "a photograph of an astronaut riding a horse" --H 512 --W 512 --seed 27 --n_iter 2 --n_samples 10 --ddim_steps 50
Global seed set to 27
Loading model from models/ldm/stable-diffusion-v1/model.ckpt
Traceback (most recent call last):
  File "optimizedSD/optimized_txt2img.py", line 184, in <module>
    sd = load_model_from_config(f"{ckpt}")
  File "optimizedSD/optimized_txt2img.py", line 29, in load_model_from_config
    pl_sd = torch.load(ckpt, map_location="cpu")
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/serialization.py", line 699, in load
    with _open_file_like(f, 'rb') as opened_file:
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/serialization.py", line 231, in _open_file_like
    return _open_file(name_or_buffer, mode)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/site-packages/torch/serialization.py", line 212, in __init__
    super(_open_file, self).__init__(open(name, mode))
FileNotFoundError: [Errno 2] No such file or directory: 'models/ldm/stable-diffusion-v1/model.ckpt'

おっと、モデルを新たに置き直さないと行けない。
サクッとコピーして、再度実行する

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# python optimizedSD/optimized_txt2img.py --prompt "a photograph of an astronaut riding a horse" --H 512 --W 512 --seed 27 --n_iter 2 --n_samples 10 --ddim_steps 50
Global seed set to 27
Loading model from models/ldm/stable-diffusion-v1/model.ckpt
Global Step: 470000
Traceback (most recent call last):
  File "optimizedSD/optimized_txt2img.py", line 204, in <module>
    model = instantiate_from_config(config.modelUNet)
  File "/stable-diffusion/ldm/util.py", line 85, in instantiate_from_config
    return get_obj_from_str(config["target"])(**config.get("params", dict()))
  File "/stable-diffusion/ldm/util.py", line 93, in get_obj_from_str
    return getattr(importlib.import_module(module, package=None), cls)
  File "/opt/miniconda3/envs/ldm/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'optimizedSD'

あれ、何だ?optimizedSDがない?

調べてみると、新しくディレクトリ作って作業しているので、PythonのEnvを作り直す必要があるそうだ

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# conda deactivate       
(base) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# conda remove -n ldm --all
(base) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# conda env create -f environment.yaml 
(base) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# conda activate ldm

よし、気を取り直して実行だ

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# python optimizedSD/optimized_txt2img.py --prompt "a photograph of an astronaut riding a horse" --H 512 --W 512 --seed 27 --n_iter 2 --n_samples 10 --ddim_steps 50
Global seed set to 27
Loading model from models/ldm/stable-diffusion-v1/model.ckpt
Global Step: 470000
UNet: Running in eps-prediction mode
CondStage: Running in eps-prediction mode
Downloading: "https://github.com/DagnyT/hardnet/raw/master/pretrained/train_liberty_with_aug/checkpoint_liberty_with_aug.pth" to /root/.cache/torch/hub/checkpoints/checkpoint_liberty_with_aug.pth
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5.10M/5.10M [00:00<00:00, 21.2MB/s]
Downloading: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| 939k/939k [00:01<00:00, 854kB/s]
Downloading: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| 512k/512k [00:00<00:00, 567kB/s]
Downloading: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 389/389 [00:00<00:00, 366kB/s]
Downloading: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 905/905 [00:00<00:00, 804kB/s]
Downloading: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 4.31k/4.31k [00:00<00:00, 3.92MB/s]
Downloading: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.59G/1.59G [00:59<00:00, 28.5MB/s]
Killed

いきなり殺された。。。

stable_diffusion.openvino を WSL2 で実行したけど”Killed” されちゃった人へ
https://zenn.dev/suzuki5080/articles/1438d52377b9df

調べてみると、これも結局はメモリが不足しているために発生しているという可能性が高い。
そして、WSL2に対する割当メモリを変えることで、この問題は解消する可能性が!

[wsl2]
memory=12GB

.wslconfigファイルを配備して、再起動。
そして再チャレンジ

(ldm) root@21feb17171f4:/workspaces/StableDiffusion2/basujindal/stable-diffusion# python optimizedSD/optimized_txt2img.py --prompt "a photograph of an astronaut riding a horse" --H 512 --W 512 --seed 27 --n_iter 2 --n_samples 10 --ddim_steps 50
Global seed set to 27
Loading model from models/ldm/stable-diffusion-v1/model.ckpt
Global Step: 470000
UNet: Running in eps-prediction mode
CondStage: Running in eps-prediction mode
FirstStage: Running in eps-prediction mode
making attention of type 'vanilla' with 512 in_channels
Working with z of shape (1, 4, 32, 32) = 4096 dimensions.
making attention of type 'vanilla' with 512 in_channels
Sampling:   0%|                                                                                                                             | 0/2 [00:00<?, ?it/sseeds used =  [27, 28, 29, 30, 31, 32, 33, 34, 35, 36]                                                                                       | 0/1 [00:00<?, ?it/s]
Data shape for PLMS sampling is [10, 4, 64, 64]
Running PLMS Sampling with 50 timesteps
PLMS Sampler: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [06:46<00:00,  8.13s/it]
torch.Size([10, 4, 64, 64])
saving images 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [06:46<00:00,  8.38s/it]
memory_final =  7.72352
data: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [07:04<00:00, 424.21s/it]
Sampling:  50%|██████████████████████████████████████████████████████████                                                          | 1/2 [07:04<07:04, 424.21s/itseeds used =  [37, 38, 39, 40, 41, 42, 43, 44, 45, 46]                                                                                       | 0/1 [00:00<?, ?it/s]
Data shape for PLMS sampling is [10, 4, 64, 64]
Running PLMS Sampling with 50 timesteps
PLMS Sampler: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [07:19<00:00,  8.79s/it]
torch.Size([10, 4, 64, 64])
saving images 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [07:19<00:00,  8.62s/it]
memory_final =  6.833664
data: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [07:27<00:00, 447.21s/it]
Sampling: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [14:31<00:00, 435.71s/it]
Samples finished in 15.12 minutes and exported to outputs/txt2img-samples/a_photograph_of_an_astronaut_riding_a_horse
 Seeds used = 27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46

できた!できたよ、ママン!

ようやく、なんとかStable Diffusionを動かすことが出来る環境を作ることができました。
Pythonに関する知識不足もさることながら、メモリ周りで苦労しますね。

せっかく環境を作ることができたので、もう少し触って遊んでみようと思っています

画像生成AIを触ってみた(未完)

少し前から結構色々な、画像生成AIが話題になっている。
LINEでテキストメッセージを送ると画像を返してくれるような、簡単に使えるようなものを作ってくれる人もいて、早速フレンドになったはいいものの、すぐに制限に引っかかってしまい、面白くない。

というわけで、公開されている内容なので自前で用意してみようと考えた

Stable Diffusion

公開されている画像生成AIで、一番メジャーそうなのはこの「Stable Diffusion」のようなので、まずはそちらを使ってみることにした。
使うにはNVIDIAのボードを積んでいる必要があるようだ。ちなみに私のラップトップのスペックはこんな感じだ

CPU:AMD Ryzen 9 5900HS with Radeon Graphics 3.30 GHz
Memory:16G
GPU0:NVIDIA GeForce RTX 3050 Ti Laptop GPU
GPU1:AMD Radeon(TM) Graphics

前準備

Docker Desktopは入っているものとします。
また、NVIDIAのCUDA Toolkitを入れる必要があるそうです
https://developer.nvidia.com/cuda-downloads

Hugging Faceから学習済みモデルを取得

Hugging Faceという、学習済みのモデルやデータセットなどを公開してくれているサイトがあるので、そちらで公開されているStable Diffusion用のモデルを使用します

HuggingFace
https://huggingface.co/


右上の「Sign Up」からアカウントを作成します。
必要事項を入力し、最終的にメールによるアクティベートを行った後に、モデルの利用申請を行います

公開されているモデルはいくつかありますが、今回は一番新しいv1-4を使いますので、こちらのページに行きます

CompVis/stable-diffusion-v1-4
https://huggingface.co/CompVis/stable-diffusion-v1-4

ライセンス条項を確認して、チェックを行い、リポジトリへのアクセス許可を得ます。

その後、ローカルにて下記コマンドでモデルをダウンロードします

>git clone https://huggingface.co/CompVis/stable-diffusion-v-1-4-original
Cloning into 'stable-diffusion-v-1-4-original'...
remote: Enumerating objects: 54, done.
remote: Counting objects: 100% (54/54), done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 54 (delta 22), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (54/54), 71.74 KiB | 282.00 KiB/s, done.
Updating files: 100% (5/5), done.
Filtering content: 100% (2/2), 7.14 GiB | 14.32 MiB/s, done.

>dir
stable-diffusion-v-1-4-original のディレクトリ

2022/09/04  22:31    <DIR>          .
2022/09/04  22:23    <DIR>          ..
2022/09/04  22:23             1,478 .gitattributes
2022/09/04  22:23            11,891 README.md
2022/09/04  22:32     7,703,807,346 sd-v1-4-full-ema.ckpt
2022/09/04  22:29     4,265,380,512 sd-v1-4.ckpt
2022/09/04  22:23            71,237 v1-variants-scores.jpg
               5 個のファイル      11,969,272,464 バイト

clone すると、ユーザ・パスワードを聞かれるので HuggingFace のユーザ名/パスワードを入力します。
clone結果としては上記のような形で、11GBほどファイルがありますね。。。

sd-v1-4.ckptmodel.ckptにリネームしておきます。

Dockerでの環境構築

Dockerのベースイメージに関してはNVIDIA Cloudのものを利用すると良さそうと偉い人が言っているので素直に真似る

FROM nvcr.io/nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04

ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo

RUN apt-get update && apt-get install -y wget git git-lfs libglib2.0-0 libsm6 libxrender1 libxext-dev

RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh && \
    sh Miniconda3-latest-Linux-x86_64.sh -b -p /opt/miniconda3 && \
    rm -r Miniconda3-latest-Linux-x86_64.sh

ENV PATH /opt/miniconda3/bin:$PATH

RUN git clone https://github.com/CompVis/stable-diffusion && \
    cd stable-diffusion && \
    conda init bash && \
    conda env create -f environment.yaml && \
    echo "conda activate ldm" >> ~/.bashrc

さらに、DockerComposeを用意する

version: '3'
services:
  app:
    build: .
    working_dir: /stable-diffusion
    tty: true
    volumes:
      - ./stable-diffusion-v-1-4-original/:/stable-diffusion/models/ldm/stable-diffusion-v1/
      - ./outputs:/stable-diffusion/outputs
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]
    environment: 
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all

さて、動かすぞ

>docker-compose up --build
[+] Building 2.1s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 717B                                                                               0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load metadata for nvcr.io/nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04                             2.0s
 => [1/4] FROM nvcr.io/nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04@sha256:4ee00dd83e88e75739870df5ac67ec38bea09  0.0s
 => CACHED [2/4] RUN apt-get update && apt-get install -y wget git git-lfs libglib2.0-0 libsm6 libxrender1 libxex  0.0s
 => CACHED [3/4] RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh &&     sh Minicon  0.0s
 => CACHED [4/4] RUN git clone https://github.com/CompVis/stable-diffusion &&     cd stable-diffusion &&     cond  0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:5d2c7f98241a55c1f2b608d865bfb22e09b1f91dc425d86db7a55d8e2b4d7b07                       0.0s
 => => naming to docker.io/library/stablediffusion-app                                                             0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
[+] Running 1/0
 - Container stablediffusion_app_1  Recreated                                                                      0.1s
Attaching to stablediffusion-app-1

シーン。。。。

ここから、うんともすんとも言わなくなってしまった。
せめてエラーでも出してくれればいいのだが、いくら待っても何度やり直しても結果が変わらないので、きっと何かが足りないのであろう。。。
げせぬ

というわけで、一旦Docker Composeは諦めて、DevContainerで試行錯誤してみることにした。
続きは明日。。

参考: Stable DiffusionをDockerで動かすhttps://zenn.dev/choshicure/scraps/14bca2492bf49f

SmartMirror妄想

先日、AWS のオンラインセミナーシリーズであるBlack Beltを見ていたら、こんなものが

見る限りでは、まだまだ改良の余地がありそうな顧客体験に感じるけれど、ちょっと未来的ですよね、SmartMirror。

そこで、SmartMirrorに関してちょっと調べてみた

SmartMirrorの仕組み

そもそもの話、鏡とは?ということに関してもちゃんと知らないことに気がつく。
そもそも鏡とガラスってどう作られるのか?ガラスはなんか砂を溶かしてやるって漫画で見たぞ?

こちらのサイトを見る限りでは、鏡=ガラス+銀 or アルミニウム背面のようだ。

SmartMirrorでは、背面としてディスプレイを使うし、鏡自体もマジックミラーを使うらしい。

ラズパイを用いる

作り上げるにはRaspberryPiを使うと、すでに世の中にはノウハウが溜まっていて楽そうだ。特にOSSでMagicMirrorを作るためのプラットフォームが用意されている

MagicMirror²
https://magicmirror.builders/

調べてみるとYouTubeにもDIY動画などが上がっていて、意外と簡単に作ることができそうだ。

何に使うのか

実装そのものは、技術的には別に問題なくできそうだ。
とは言え、作ったとして何にどう使うのか?を考えてみたい。

事例としてよく挙げられている内容としては、鏡に天気予報やニュース、メッセージなどを出すということなんだけど・・・

スマホでいいよね?

という結論に至ってしまう。もしくはスマートウォッチ。

鏡に文字が浮かび上がるのは、未来感もあるし、言ってしまうとSF的な感じもする。
ロマンだ

だけどせっかくなら有用な利用用途を考え出したい。

スマホなどと違って、鏡であること。
それであって、RaspberryPiで出来るレベルの表現

思いつかないな。。。

とりあえず、いつの日かロマンを追い求めて作り出すかもしれないので、見つけたサイトを備忘録に載せておくことにする