(軽量化)BERTScoreで文章を類似度順に並べる

以前、自然言語の評価基準「BERTScore」を使って、類似度の高い文章をスコア順に並べました。しかし、あまりにも計算が遅かったので軽量化します。

この記事について

自然言語処理をとりあえず試してみたい人がターゲットです。自然言語処理で登場する、難しい計算や図について、私はよく分かりません。

分からなくても何とか出来ることを、実感できればと思います。

事前準備

環境の用意や、参考サイトは以前の記事をご確認ください。

テストする文章も前回と同じです。

この4つの文章を他3つの文章と比べ、類似度のスコアを出しましょう。

前回のコードは単純な総当たりでの類似度計算で、500件くらいの文章を処理すると3日かかりました。

コードに無駄が多かったので改修します。

文章Aと文章B、文章Bと文章Aの組み合わせ計算は同じなので、再計算しないようにしています。

軽量化したPythonコード

出力結果

0.7528というような数字が類似度のスコアです。

高いほど似ている文章となります。スコアとしては「吾輩は猫である」と、「未来の世界の猫である」が最も類似していることになります。

計算速度アップ

前回28.5秒だった計算が、22.8秒になりました。

4件だと微妙な速度アップですが、大量の計算だと1日差がでることもあるでしょう。

Pythonでインクリメント演算子「++」が使えない

Pythonでインクリメント演算子「++」が使えません。累算代入「+=」を使います。JavaScriptから来た人には、つまづくところかもしれません。

インクリメント演算子

Pythonで変数「n」に1追加したく、「n++」と書いてみました。するとエラーがでます。

運よく隣にPythonエンジニアがいたので、何でエラーなのか尋ねました。

「Pythonでインクリメント演算子は使えません。」と教えてくれます。

・・・初歩的なことかもしれませんが、「++」をインクリメント演算子というのですね。

累算代入を使ってください

Pythonではインクリメント演算子の代わりに、累計代入「n += 1」と書くようです。

私が「インクリメント演算子」という言葉を知っていれば簡単に検索して解決できましたが・・・「++」を何と検索すればよいか迷ってエンジニアさんに聞いてしまいました。

忘れないように、備忘録として残します。

開閉パネルに適度なアニメーション

前回、アクセシビリティを確保した開閉パネルを作りました。瞬時に開閉するパネルも良いですが、場合によってはアニメーションを付けたほうが使いやすいこともあります。

開閉パネルサンプル

今回はアクセシビリティを確保しつつ、アニメーションしながら開閉するパネルを作りました。

最も簡単と思われるjQueryを利用しています。

アニメーション開閉パネルのコード

サンプルページのコードを抜粋します。

slideToggle(200) メソッドを使い、0.2秒かけて開閉させます。

アニメーションは必要?

変化を伝えるとき、アニメーションが有効になる場合があります。

開閉パネルのように、ボタンを押して画面の一部が瞬時に変化する場合、どう変わったか理解する時間が必要になります。

変化時間 < 変化理解時間

開閉パネルが変化したことを理解する時間が、変化アニメーションの時間より長い場合は、アニメーションを実装したほうが良いでしょう。

ユーザー傾向で判断が変わります。

リテラシーが低めのユーザーを想定するなら、アニメーションがあったほうが良いですし、同じユーザーが短期間に何度も使うような開閉パネルであれば、アニメーションがない方がストレスを減らせます。

例えば業務システムの開閉パネルであれば、担当者が何度も操作することが想定されるので、アニメーションなしの方がストレスなく使えます。

ブログ投稿やCMSで使われるWordPressの投稿画面も、開閉パネルはアニメーションがありません。

アニメーションする場合の速度は?

サンプルで作った開閉パネルのサイズであれば、200ms(0.2秒)で良いと思います。

jQueryのslideToggle()はデフォルトが400ms(0.4秒)で少し遅く感じます。

速度の目安として、Googleマテリアルデザインガイドラインの速度に関する記述を参考にします。

変化が中くらいのアニメーションの場合、開くのが250ms、閉じるのが200msとあります。

開閉でスピードを変えるのも大変なので、200msで設定すればよいでしょう。

もし、開閉パネルが大きいのであれば、200ms~400msの間で程よく速度を調整してください。

開閉パネルには「aria-expanded」と「aria-controls」

FAQページで見かける開閉パネル。アクセシビリティを確保してコーディングするのであれば、「aria-expanded」と「aria-controls」を使います。サンプルコードを掲載しています。

WAI-ARIAに準拠しよう

コーディングでアクセシビリティが気になったら、W3CのWebアクセシビリティ仕様「WAI-ARIA」に準拠しましょう。

WAI-ARIAは日本のWeb業界では、あまり知られていない印象があります。

ただ、GoogleやAmazonなどのコードを見ると、WAI-ARIA準拠が進んでいることが分かります。

開閉サンプルページ

FAQページをサンプルにした開閉パネルのコードを、W3Cのページ(英語)で見ることができます。

もう少し実用的なCSSを適用し、WAI-ARIAに準拠した開閉パネルのサンプルを作ってみました。あわせてご確認ください。

開閉のトリガーになるボタンに「aria-expanded」と「aria-controls」を指定します。

サンプルコード(サンプルページから抜粋)

「aria-expanded」は開閉の状態をユーザーに伝えます。開いているならtrue。閉じているならfalse。

スクリーンリーダーNVDAやJAWSを使っている場合、「折りたたみ」「展開」という状態を読み上げてくれるようになります。

「aria-controls」には開閉させる要素のidを指定します。

もう一つ「aria-hidden=”true”」という、表示状態を表すWAI-ARIAを使っています。これは必須ではなく、styleの「display: none;」でもよいです。

W3Cのサンプルコードでは、styleで表示状態を切り替えていましたが、個人的には統一してaria-hiddenを指定したほうが扱いやすく感じます。

視覚障害者が笑う読み上げ

実際スクリーンリーダーを使っている視覚障害者にWAI-ARIA準拠の開閉パネルを使ってもらいました。

開閉パネルを操作して笑っていました。

聞きなれない「折りたたみ」「展開」の読み上げが面白いようです。

開閉状態を伝えることには成功しているようでした。

保守管理の面でもWAI-ARIAはお勧め

WAI-ARIAを準拠すると、コードが属人的になりにくくなるメリットがあります。

開閉パネルのHTMLをclassで指定すると、人によって名前の付け方や、操作するJavaScriptの書き方が変わってくると思います。

WAI-ARIAだと書き方が決まっています。

保守管理の面でも優れているのでお勧めです。

ブログの習慣化で心穏やかに過ごす

公開中のブログが500件を越えました。最近は自分の習慣としてブログを書くことが根付いてきたような気がします。ブログを続けて特に良かったことは、心穏やかに過ごせるようになったことです。

ブログを書く3つの目的

私がブログを書く目的です。

  • 情報発信
  • 技術・デザインのスキルアップ
  • 心穏やかに過ごす

情報発信

昔働いていた会社の上司から情報発信の大切さを教えられ、このブログを始めました。

役立ちそうな情報は、個人や会社にとどめるよりも、社会で共有したほうが良いと言われます。

実際自分もGoogle検索に引っ掛かる多くの情報に助けられ、仕事をしてきました。自分も社会に情報を還元しましょう。

記事を書いていると、年間1万ビューを越えて利用される記事もあれば、3ビューしかないような記事もあります。

ただ、ほとんど見られない記事でもピンポイントで役立つこともあり、コメントが書き込まれる場合もあります。

「社会に役立つ情報」と自分が考えても、意外と何が役立つか分からないし、ページビューが少なくても役立つことはあります。

とにかく質より量を出すことが大事かと思います。

技術・デザインのスキルアップ

発信と同時に、自分のスキルアップも目的としていました。

技術やデザインの記事を書くことで、時代に取り残されないようにします。

ブログに書くために技術を学び、忙しくても強制的に技術を学ぶ仕組みとなります。

時間が無くなりそうに見えて、逆に時間の余裕ができます。

忙しくて技術やデザインを学ぶ時間を後回しにすると、より仕事の効率が悪くなります。逆に前もって知識を蓄積したほうが、時間を作れます。

その時間でブログを書く時間も捻出できるでしょう。

また、ありがたいことに技術レベルの低い記事を書くと、「こうした方が良いんじゃない?」といった指摘を頂くこともあります。

自分だけではハマる問題を、解決してもらえることもあります。

 

しかし・・・やはり途中でブログが続かなくなり、更新頻度が落ることもありました。

心穏やかに過ごす

ブログが習慣化したのは最近です。237日前から、236日更新しています。(微妙に毎日更新ではありません。)

ブログ継続を始めたのは、妻が入院してから。心穏やかに過ごすことが目的になってからです。

妻が1か月いない状況で4人の子供を育てながら、長時間労働になりがちなWeb業界で働いていると、イライラしてしまうだろうと予想しました。

解決方法として、日々の出来事を文書化し、客観的に見ることで、イライラを他人事にしようと考えました。その手段としてブログ更新は最適です。

子供がふざけて物を壊しても、プログラミングでハマって頭を抱えても、デザインがうまく決まらず壁にぶつかっても・・・ブログのネタになると思えば気が楽になります。

ネタに困らないことに気づく

子育ても技術もめまぐるしい変化の連続なので、ネタに困ることはありません。(デザインは比較的変化が緩やかです。)

ブログを書くことを前提に生活していると、ネタ探しをするようになり、結果的に子供や技術にアンテナが向くようになります。

前述のように、技術は先回りして知識があったほうが時間の余裕ができ、より心穏やかに過ごせる時間が長くなるでしょう。

心穏やかに過ごす時間を増やすことが、ブログ継続の目的になっている気がします。

ただ習慣化してくると、目的意識自体がなくなってきて、ただなんとなくブログを更新している感じになります。

それが習慣というものなので、良い状態だと思います。

親切!ラズパイ用7インチタッチディスプレイケース

ラズパイ用の7インチタッチディスプレイケースがあります。組み立ててみると、非常に親切にできていることに驚きました。

ラズパイ4とタッチディスプレイケース

ラズパイ4を購入しました。合わせてケースとディスプレイと冷却ファンが欲しいと思ったとき、良い商品がありました。

7インチタッチパネルディスプレイと冷却ファンの一体型ケースです。ラズパイ4だけでなく、3でも利用できます。

UPERFECTという中国のブランドで、説明書は若干分かりにくいところもありますが、それでも親切にできています。

組み立ては簡単なので、説明書なしでも組み立てられます。

フタを開ける

ねじ止めされたケースのふたを開けます。ドライバーが付属しており、すぐに開けられます。

USBとHDMIにコネクタを挿す

タッチパネルはUSB接続か、はんだ付けを選べます。

手軽なUSB接続と、配線をスッキリさせるはんだ付けを選べるところが良いです。

今回は簡単にUSBに挿しました。USBを抜けばタッチ不要なときに消費電力を抑えられるかもしれません。

電源用Type-Cコネクタと、HDMI-Dコネクタもそれぞれ挿します。

コネクタに分かりやすく「Type-C」と書いてあるのが親切です。

ラズパイをケースに取り付ける

最後にラズパイをケースにねじ止めする作業です。

ここで注意があります。

ラズパイをねじ止めしてしまうと、SDカードを入れることが非常に困難になります。

ケースとラズパイ同時購入の場合、ねじ止め前にOSをインストールしたSDカードを挿しましょう。

あと個人的なミスですが、タッチパネルのコネクタをケース側につなぐ前に、側面のボードを付けるのを忘れました。

側面ボードは2つあり、ラズパイ4用は「PI4」と書かれています。

このブランド、かなり親切です。

ACアダプターを挿すと起動

トラブルなくラズパイ4が起動し、ディスプレイが映りました。

思ったよりファンの音が大きいです。

説明書を改めて読むと、ファンはディスプレイ上にある設定ボタンから、ON/OFFを切り替えられるようです。

軽い処理をするときや、部屋が寒い時は、OFFでも良いかもしれません。

組み立てのしやすさ、程よい選択肢。

とても親切なタッチディスプレイケースだと思います。

ホットカーペットの修理※消費電力の小さいもの

1人用ホットカーペットが壊れました。スイッチを入れても温かくなりません。昔なら捨てていますが、電子工作を学んだおかげで、修理して使うことができるようになりました。

2か月前に買ったばかり

Amazonで「アイリスオーヤマ ホットマット 60×60cm ブラウン HCM-60S-T」を2か月前買いました。

すぐに壊れたのは製品の問題でなく、うちの家庭の問題です。

男の子4人、ガサツであらゆるものが壊れていきます。

たぶん、カーペットを無理に引き延ばしたとかで、断線したのだと思います。

スイッチ部分のネジを外して、分解しましょう。

※分解する前に電源コードを抜いていることを確認しています

消費電力に注意

ホットカーペットの修理は、基本的に素人が手を出してはいけません。

私も電子工作独学の素人同然なのですが、消費電力で判断して修理します。※自己責任で

3畳用の1000Wホットカーペットは絶対に手を出してはいけません。

しかし今回の72Wのホットカーペット(ホットマット)であれば、家電としても消費電力が低い方です。

100W以下なら火災リスクが限りなく低いと判断しましたが、あくまで感覚知です。

万全を期するなら防炎スプレーをカーペットに噴射してもよいかもしれません。

断線していた

分解して基板を確認したところ、配線の一部が断線していました。

はんだ付けで直せそうです。

はんだで断線したコードをつなぎました。

修理完了

電源を入れてみると、ホットカーペットが温かくなりました。修理完了です。

子供がいる家庭だと、家電やオモチャが高確率で壊れると思います。

何度も自分で修理する機会があれば節約になります。また、修理して物を長く扱えることを子供に伝えられます。

そもそも物を壊さないよう、大切に扱うことを、子供たちに伝える必要があるでしょう・・・。

ただ、親が修理できるスキルを持つと、感情的に子供を怒る確率は減るのが良いところです。

「壊した!?買ったばかりでOOOO円もしたんだぞ!弁償だぁ!」

「壊した?直そうか。壊れた原因は無理に基板付近のカーペットを引っ張ったこと。中で断線が起こったんだ。修理を手伝って。」

と、変わります。

Node.jsとブラウザでWebカメラの写真をローカルに保存

ブラウザで動くWebカメラアプリを作ります。撮影した写真をNode.jsでローカルサーバーに保存していきます。

開発環境

OS:raspbian 10.7(WindowsやMacでも問題ないと思います)
Node.js 10.21.0

Node.js モジュール

fs
Express
Socket.IO

撮影から保存までの流れ

Webカメラで撮影

カメラ映像をcanvasに転写

保存ボタンが押されたら、canvas画像をbase64にエンコード

base64(画像をテキスト化したもの)をWebSocketでNode.jsサーバーに送信

Node.jsサーバーで受信したbase64データをデコード

デコードした画像を任意の場所に保存

まずはWebカメラ設置

最初にWebカメラの設置します。(もちろん端末内臓カメラでもOKです)

画質やフォーカス性能は、Webカメラの性能次第になります。

今回はモルモットのケージにカメラを取り付けました。

Node.jsのコード

Node.jsでExpressを使い、Webサーバーにしています。

Socket.IO(WebSocket)で受信したbase64データをデコードし、「record」ディレクトリに画像の保存します。

「htdocs」ディレクトリ内にindex.htmlを置くと、http://localhost:3000/でアクセスできます。

このindex.htmlにカメラアプリのフロント側コードを書きます。

フロント側のHTMLコード

Webカメラ映像をcanvasに転写します。そしてページ上の保存ボタンが押されたら、canvas画像をbase64にエンコードします。

次に、base64画像をWebSocketでNode.jsサーバーに送信しています。その時あわせて撮影日時を「年-月-日T時分秒」で送信します。

撮影日時をファイル名に使えば、保存した画像の上書きは防げます。(1秒以内に連写しなければ)

Webカメラの解像度は、端末スペックにより調整してください。

ラズパイ3で720p画像だと、処理が追い付かないのか、たまに荒れます。

あまり動きのないものを撮影する場合は、フレームレート(canvas転写頻度)を落としても良いでしょう。

setInterval(draw, 100);の数字を変更すると、撮影間隔が変わります。

実際に保存された写真

「2021-02-22T085213.jpg」という名前で保存されました。

余談ですが、モルモットが寝ているところを初めてみました。近づくと目を開けるため、いつ寝ているか分かりませんでした。

タイムラプスや防犯カメラ、機械学習に

今回、写真撮影のトリガーは「保存」ボタンでした。

ラズパイを常時稼働させている場合、トリガーを変えれば、さまざまな使い方ができるでしょう。

例えば植物の成長記録。タイマーをトリガーにして毎時間経過を撮影し、写真をつなげてタイムラプスにもできます。

人感センサーと組み合わせれば、防犯カメラにもなるでしょう。

タイマーやセンサーと組み合わせ、機械学習用の画像を蓄積していくのにも向いていると思います。

私の場合はラズパイのサーマルカメラで体温を毎朝測るので、その際顔の写真を保存して、健康状態(目の下のクマの様子など)を検証しようと思います。

ラズパイディスプレイをNode.jsでON/OFF

常時稼働中のラズパイで、Node.jsを使ってディスプレイのON/OFFを制御します。ディスプレイを見ることがない夜間は電源OFFにするなど、節電に利用できます。

開発環境

Raspberry Pi 3 Model B+
OS:raspbian 10.7
Node.js 10.21.0

Node.js モジュール

child_process

シェルコマンドでディスプレイ制御

ラズパイのディスプレイは、シェルコマンドでON/OFFを切り替えられます。

ディスプレイON

ティスプレイOFF

シェルコマンドをNode.jsから実行できれば、任意のタイミングでディスプレイのON/OFFを切り替えられるようになります。

シェルコマンドをNode.jsで実行

child_processモジュールを使うことで、Node.jsからディスプレイ制御ができるようになります。

ディスプレイの電源をOFFにして、3秒後にONにするコードは下記です。

これで動作確認ができると思います。

実用では、Node Cronを使って〇時にディスプレイONや、光センサーで暗くなったらディスプレイOFFなど、タイマーやセンサーと組み合わせて使うと良いでしょう。

Node.jsでブラウザからCSVを保存する

ブラウザのHTMLに入力した値を、Node.js経由でCSVに記録します。Webページの「記録」ボタンを押すと、現在時刻と温度が記録されるサンプルを作りました。Node.jsモジュール「CSV Writer」を使うと簡単に実現できます。

開発環境

OS:raspbian 10.7(WindowsやMacでも問題ないと思います)
Node.js 10.21.0

Node.js モジュール

CSV Writer
Express
Socket.IO

Node.jsのコード

事前に上記3つのモジュールをインストールします。

CSV Writer」はnpmのサイトにインストール方法やサンプルコードがあるので参考にしました。

Node.jsのコードです。

ブラウザからSocket.IOで受け取ったデータを、CSV Writerで書き込みます。

書き込み終わったらまた、ブラウザに(‘recorded’, true)と戻しています。

ブラウザ側のHTMLコード

データ送信画面のHTMLを作ります。

「記録」ボタンを押すと、テキスト入力欄の値がSocket.IOでNode.jsサーバーに渡ります。

CSVで保存用に、[{“date”: 日付, “temp”: 値}]という配列でデータは渡します。

Expressで指定した場所(htdocs)に、このHTMLを配置します。

「記録」ボタンでCSVに保存

Node.jsでhttp://localhost:3000を立ち上げ、制作したHTMLをブラウザで開きます。

「記録」ボタンを押してみましょう。

正常に動けば、「記録中…」と一瞬ボタンが変わって、CSV書き込み完了後に「記録完了」という表示になります。

「記録」ボタンを押すたびに、データがCSVに追記されていきます。

記録されたCSVファイルは、「[Node.jsを置いたディレクトリ]/record/data.csv」に保存されます。

エクセルやメモ帳でCSVを開き、送信データが正しく書き込まれていれば成功です。