09

一歩進むと何歩でも戻れる

前回も書いたが最近自然言語処理に興味が出てきたのでいろいろやってみているが、あまりすすんでいない。

KNP が無限ループにはまる問題

どうもこの文字列が問題のようだ

ヽ(´▽`)ノ

とくに

ヽ(´

これ。 これを jumanpp に食わせるとこんな結果が得られる

ヽ ヽ ヽ 特殊 1 記号 5 * 0 * 0 NIL
(´ 記号 特殊 `) 0 0 0 0 0 0 0 "*"
EOS

これを knp に渡すと Segmentation Fault になる。 この先の調査はまた次回だな・・・。

言語による概念の圧縮率

そんなこんなで最近この話が気になっている

だから別に服なんてよくね?

  • よくね?
    • 服よくね?
    • たぶん「(問題にしなくても)良いだろう」の意
    • 相手の考えが何かにこだわって/とらわれており、それに対する指摘、もしくは反論の意を含んでいる
    • 言い方として砕けているので、つまりそういう状況下である
  • 別に
    • 別によくね?
      • 「別に(特段)(問題にしなくても)いいだろう」
      • 問題にかかっているかもしれない
    • よくねで指摘している相手の考え(問題にしていること)について、相手はこだわっているが話者にとっては大した問題ではない・あるいは理解不能であるという主張の補強
  • だから
    • この文の前の話を受ける
    • 相手の表明に対する反対の意、もしくは自分の意見が正しい
    • 話者がすでに述べた(つもりである)何かしらを再び述べようとしている
    • 反対の意、もしくは自分の意見が正しい、また何かしら同じことを再び述べているのであるということを相手に強調している
  • なんて
    • 服なんて
    • それが大した問題ではないと認識している
    • それが大した問題ではないと強調している

語順なんてどうでもいいのだと思って取り上げてみたけど、細かく砕いてみると意外とこの語順にも意味があるのかもしれない。「よくね?」に「別に」が追いかけて、「だから」が出てきたのはなんか言い添えないといい足りないということを言いながら感じたというような印象を受ける。上記でだからのところに反対の意とかいたのは、「だから別に服なんてよくね?」という語順でとらえたならそうなりうると思ったんだけど、単に「よくね?別に」では足りないことを補うために出てきた言葉のようにも思える。

しかし意外と服のことだけじゃなくて、相手の考えていること(を、話者がどう感じているか)と、それに対して話者の主張したいことをいろいろな言葉の端にとらえることができるのだが、これはつまりどういうことなんだろう。

進めない日常

ここ一月ほどTwitterの日本語を解析してみたくて、係り受け解析に手を出してみている。 ちなみに何も(本当に何も)できていません。 その状況報告。

KNP
  • Cabocha と KNPがメジャーどころらしい。ざっと評判を眺めたところ、KNPの方が精度がよさそうだったのでインストールを試みる
  • Amazon Lightsail の最小インスタンスが余っていたのでそこで作業をしていたのだが、この程度のインスタンスだと juman と knp 自体のインストールは可能だが、juman++ はコンパイルに失敗する。メモリ不足のためと思われるが、詳しい原因はよく知らない。
  • juman++のみ別のインスタンスでコンパイル済みのものを導入した
  • pyknp をインストールしてPythonから呼び出せることは確認できた。
  • 半角空白、改行コード、絵文字を取り扱うのはまずいらしいので、全社2つは全角空白に、絵文字は単純に削除して pyknp に渡してみる
  • 何かわからないが不正な文字列があるとしてエラーになる部分が多々(エラーなく解析できる部分もある)
  • エラーはとりあえずパスして続行するも、特定の箇所で無限ループにはまって止まる。
  • ちょっとソースのぞいてみたところ、おそらくサブプロセスを起動してその出力を待っているような雰囲気なのだが、サブプロセスのアウトプットがループから抜ける条件に合致しないのだと思う。たぶんこのサブプロセスはKNPのバイナリを起動しているのだろうが・・・。
StanfordNLP
  • そんなことではまっているうちに、 stanfordnlp とかいうのが出たという情報をキャッチ。
  • 試そうとしてみるも、Lightsailの方ではやはりメモリが足りない。
  • 別途もうすこしメモリのあるインスタンスではインストールはできるものの、Cent OSが6系だったのでglibc のバージョンが合わないらしく、実行できない。
  • Centos 6でglibcをインストールする方法はないでもないらしいが、この上にいろいろ構築することを考えると、単純にCentos7にしてしまったほうがよかろうということでOSごと環境を作り直し。
  • stanfordnlp のインストールはできたものの、最初のサンプルでさえ動かない。 Vector が見つからないとか。何の?
追記

Windows/Anaconda だとモデルのダウンロードでrmコマンドを実行しているというエラーが出るが、解析自体はできる模様で

>>> doc = nlp("きょうもいいてんきですね")
>>> doc.sentences[0].print_tokens()
<Token index=1;words=[<Word index=1;text=きょうも;lemma=きょうも;upos=ADV;xpos=_;feats=_;governor=2;dependency_relation=advmod>]>
<Token index=2;words=[<Word index=2;text=いい;lemma=いい;upos=ADJ;xpos=_;feats=_;governor=0;dependency_relation=root>]>
<Token index=3;words=[<Word index=3;text=て;lemma=て;upos=SCONJ;xpos=_;feats=_;governor=2;dependency_relation=mark>]>
<Token index=4;words=[<Word index=4;text=ん;lemma=ない;upos=AUX;xpos=_;feats=_;governor=2;dependency_relation=aux>]>
<Token index=5;words=[<Word index=5;text=き;lemma=来る;upos=AUX;xpos=_;feats=_;governor=2;dependency_relation=aux>]>
<Token index=6;words=[<Word index=6;text=です;lemma=だ;upos=AUX;xpos=_;feats=_;governor=2;dependency_relation=cop>]>
<Token index=7;words=[<Word index=7;text=ね;lemma=ね;upos=PART;xpos=_;feats=_;governor=2;dependency_relation=mark>]>
>>> doc = nlp("今日もいい天気ですね")")")
>>> doc.sentences[0].print_tokens()")
<Token index=1;words=[<Word index=1;text=今日;lemma=今日;upos=NOUN;xpos=_;feats=_;governor=3;dependency_relation=obl>]>
<Token index=2;words=[<Word index=2;text=も;lemma=も;upos=ADP;xpos=_;feats=_;governor=1;dependency_relation=case>]>
<Token index=3;words=[<Word index=3;text=いい;lemma=いい;upos=ADJ;xpos=_;feats=_;governor=4;dependency_relation=acl>]>
<Token index=4;words=[<Word index=4;text=天気;lemma=天気;upos=NOUN;xpos=_;feats=_;governor=0;dependency_relation=root>]>
<Token index=5;words=[<Word index=5;text=です;lemma=だ;upos=AUX;xpos=_;feats=_;governor=4;dependency_relation=cop>]>
<Token index=6;words=[<Word index=6;text=ね;lemma=ね;upos=PART;xpos=_;feats=_;governor=4;dependency_relation=mark>]>

うーん

Why trackball

  • 机が狭い
  • 今更トラックポイントでもない
  • タッチパッドはWindows ではMacほど有効でない

腱鞘炎というわけでは、ない

というわけで

うっかり自宅用にトラックボールを買ってみたら意外と慣れてしまったので勢い余って職場用のを買ってみたらどうも失敗したようだという話。 買ったのは以下の2製品。

別にElecom縛りってことではないんだけど、個人的にはケンジントンのでかいやつは無理だろうと思って避けたものの、ロジクールのは普通に評判が良いようなので選択肢としてありだとは思っている。近くの電気店にはElecom以外のトラックボールの扱いがなかった。

で 多分 M-XT3DRBK (前者)が EX-G で M-XPT1MRXBK (後者)がEX-G Pro ってことになっているんだと思うんだけど、その名の通りEX-G Proのほうがボタンが多かったり、作りの細部にこだわりがありそうな感じもあったりで値段も倍くらいする。最初自宅用に EX-G を買って、使ってみたところ最初の1時間くらいは何か腕の筋にいやな痛みがあるような感覚があったのだけど、そのまま作業に集中して数時間使っていたら慣れてしまった。場所も取らないし操作感も軽くてよいので、職場のマウスがちょうど何やらへたってきたので、いいタイミングと思って上位グレードと思われる EX-G Proを購入した。

だがどうも様子がおかしい。

ぱっと見てわかるのはEX-G ProはボールがEX-Gと比較すると上に向いている。多分このせいではと思うのだが、ボールに働いている慣性もしくは摩擦が大きくなっている気がする。つまり、細かく正確に動かすことが難しい。力(というほどではもちろんないのだが)を入れなければボールが動き出さないし、一度動き出すとすぐに止まらないというような。しかし値段が倍もする上位モデルが下位モデルより動きがぎこちないなんてことあるだろうか?

また一見して分かりにくいが、EX-G ProはEX-Gに比較してサイド部分にボタンが増えており、専用のソフトウェアでボタンの動作をカスタマイズできる。EX-Gのほうは、もともと機能の割り当てられたボタンはあるものの、カスタマイズなんてことはできない*1。が、Ex-Gの一番右のボタンに割り当てられている、「押下されている間だけカウント数を下げる」という機能は、EX-G Proに割り当てることができるキーの機能として存在しない(ように見える)。値段が倍もする直系の上位モデルが下位モデルより機能が足りないなんてことがあるだろうか?

Amazonのレビューでは後者が高得点なのだけど、個人的にはどう考えても評価が逆だ。まだ長期間使ってのレビューではないので、耐久性などの観点ではどうかわからない。しかしどう考えてもProのほうが使いにくい。

追記

ほかにも気になる点

  • PROのほうがクリック音やホイールの回転音が大きい
  • PROのほうがサイズが大きいので、本体に対して手をのせる形になる。そのためか、右側のボタンをうっかり押してしまうことがある
  • PROのホイールは回転が固い。そのためホイールの一番本体から遠いポイントを撫でて操作すると余計な力がかかってしまうのかホイールクリックになりがち。手前側を撫でるように操作する必要がある。

*1:と思っているが、もしかして同じソフトウェアを使用すれば可能なのか?という疑問がたった今脳裏をかすめた

職人作業を Jenkinsfile にした

もう新しくもない話になるが、 Jenkins 2 になってから、Jenkinsfile というDSLで記載したファイルにビルドパイプラインの定義をスクリプトとして記述することができるようになっている。 テキストで書けるようになることでバージョン管理による差分の検出・追跡が可能になる。Infrastructure as Code のトレンドがあった影響だとは思うが、まあJenkins自体が重量級なのでどうなのか。と思うところはあるが、ないよりは断然良い。

自分の所属先ではパッケージ型のプロダクトを持っており、以前よりそのビルドやリリースのためにJenkinsは利用している。新しいリリースを計画するたびに以前のジョブをいくつかコピーしながら新しいリリース向けのビルドジョブを作成し、それらをつなげてリリースパイプラインにしていた。 これらのインフラは作ったのも自分なので、何となく毎回なにが必要なのかはわかってはいるのだが、いまいち定型化できないし説明も難しい感じがしていた。とりあえずリリースにあたってやる必要のあることを整理する目的で、今回の一連のビルドの一部(特にリリースに関する部分)をJenkinsfileにした。

Jenkinsfile自体2通りの書き方があるらしい。Declarative PipelineとScripted Pipelineといって前者はあくまで宣言的に記述していくのに対して後者はGroovyスクリプトを混ぜ込めるというか、Groovyとして評価されるっぽい?一応前者は pipeline の宣言がルートにあり、後者はそうではないということになっているらしいのだが、この区別はほんとにそうなのかよくわからない。というか、特に興味がないのであまりこれらの違いに関して理解していない。 というのも、Declarative Pipelineでは柔軟なビルドパイプラインの定義が難しいと感じたため、結構Groovyスクリプトを書いてしまっている。例えばDeclarativeでは繰り返しの定義や、データに従ってコンフィグが変化するビルドを定義することができない、もしくは難しい。自分の要求としては、成果物全体の姿は決まっているが、例えばパッチリリースだった場合は成果物の一部、必要な部分のみに限ってリリース対象となるため、リリース毎にリリース対象を決め、その定義に従って適当に必要な部分だけパイプラインが流れるようになってくれないと面白くない。 リリース対象の増減でパイプラインの定義を書き換える必要があるのであれば、事故のもとにもなるだろうしSCMが使えるとはいえメリットが薄れる。

これをループなしで実現するのはちょっと難しいと思われた。また確認はしていないのだが、おそらく処理の共通化が容易ではないように思われる。可能な方法としては以下のような手段が取れそうなのだが

  • ジョブを分けて、共通的なジョブは個別のジョブの下流に置く
  • Groovyスクリプトを切り出して、動的に読み込む処理を書く

ただ前者の場合、成果物がジョブのワークスペースにできると思うので、いろいろなバージョンの成果物がひとところに集まるのであれば微妙。後者の場合・・・というか、結局Groovyから逃げるなということではないのか。 そう理解をして、結局今回取っている方針は、

  • 1ファイルにリリースパイプラインのほぼすべてを記述する(単純な個別ビルドは別途定義してあって基本としてはそこから成果物を収集する)
  • 可変部分はヘッダに定数的なオブジェクトを作ってそこに定義できるようにする。
  • 次回リリース時には、ファイルはまるまるコピーしてヘッダ部分のみリリースに必要な内容に書き換えてパイプラインを作成する。

処理の共通化はしていない。してもよいのだが、共通化したファイルがどこにあれば適切なのかいまいち判断できなかったことと、過去のリリースは現在のリリースと関係ないし、共通化した処理を修正したら過去のビルドも治ってほしいということもないように思われるので毎回コピーでも許容できそうに思われたため。

JenkinsfileはSCMに放り込むのだが結局Jenkinsのビルドジョブは作る必要があるあたり微妙なのだが。Gitを使えばもうちょっと自動的にやれそうな雰囲気を感じてはいる。今のところSVNなのであまり確認できていない。 (まあでもJenkinsファイルのリポジトリだけGitにしてしまえば試せるかもしれない。)

というわけで、職人作業はほぼGroovyスクリプトになった。実際にうまく運用できるかは次回以降のリリースでも確認する必要がある。

で今のところ、 Declarative Pipeline のメリットを見いだせていない。

Arduino で 複数のサーボモータを同時に動かす

何って、単にこういうこと


20180512

Arduino本体にデジタルピン経由でボタンを二つ、I2CでPCA9685なる複数のサーボモータを制御するボードを介して3基のサーボモータを制御します。別に難しくもなんともないんですが、ソースコードをどこかに張り付けておきたいと思ったのでこんなエントリを書いている次第。

Keyestudio

最近中国は深センあたりのメーカーが元気いいらしいじゃないですか。まあ行ったことないんでよく知らないんですけど。まあArduinoはオープンなハードウェアなわけで、深センのメーカー何社からArduinoクローンが発売されています。叩き合っているのか何なのかわかりませんが、本体とそこらの入門本で使いそうなパーツをいろいろ取り揃えてパックにしたものスターターキットとして大変お安く販売されています。品質も詳しくないのでまあ高いといえるのかどうかわかりませんが、日曜工作くらいなら普通に買って不安がないくらいではあります。

で、動画に見える通り今回は Keyestudio ってとこのを使っています。黄色がかっこよかったので。しかも特に意味もなく環境モニタリングキットという、細かい電子部品の代わりにいろんなセンサーをまとめてパックにされたものを買っています。いずれ何かに使うでしょう。

(なぜかはてなのアマゾン商品紹介機能が使えないので直接アフィリンク張っておきます)

PCA9685

Arduinoから複数のサーボモータを使う場合にこういうのを使う必要がある(?)らしいです。特にArduino単体でやってみてできなかったので買った、というわけではなく、ネットで検索してたら出てきたので買ってみたというだけなのであれですが。

特に説明書も何もついてないんでどうするんだという感じなんですが、Amazonの商品ページに行くと接続例の回路図が商品画像の一部に載ってます。つまりその通り接続します。物理はそれでいいとしてソフトウェアのほうはどうするかというと、これもAmazonの商品ページ見るとわかるんですが、「Adafruit 16-Channel Servo Driverの互換品」と書かれています。なので Adarfuit のライブラリがそのまま使えます。Arduino IDEのスケッチメニューのライブラリをインクルード>ライブラリの管理 から Adafruit PWM で 検索すれば出てきます。あとはこのライブラリの使い方を適当にググりながら書けばよいという感じです。

最初付属の説明が何もなくてどうすればいいのかという状態だったので、いろいろ試行錯誤しましたが無駄でした。なので今後そんな人類が生まれてはいけないと思いここに書き記しておきます。

ソース

たいして難しくもないのですがサーボは可動可能範囲があるので、その範囲をどのくらいの値として指定する必要があるのかは製品によって違うらしいですね。なので手探りで割り出す必要がありそう。ちなみにこのソースに書いてあるのはほかの人が今回私が使用しているサーボモータと同じSG90で試したと思われる値をパクっています。

ArduinoでPCA9685を使って複数のサーボモータを回してみる

Java EE でPlugin的な拡張ってどんな扱いなの

あるウェブアプリケーションを提供する場合にプラグイン的な機構を設けて、利用するユーザごとに機能拡張であるとかカスタマイズさせたい場合、なんていうユースケースは昨今いろいろありそうではあるけど、Java EE的にそういった機構を実現するための仕様ってあるんだろうか。 基本的にウェブアプリケーションはWarという形でまとめられてしまうからそこ以外からの干渉はできない気がする(むしろ独立した環境がパッケージングされているということに意味がある感じがする) 例えば単純にあるインタフェースを持ったクラスを運用中に追加して、アプリケーションの動作を変更するなり拡張するなりができる、とした場合、追加のClasspathというか追加のクラスローダが必要になる気がするのだけどそれはアプリケーションが独自にやればいいという話でJavaEEでは仕様化されていないのかな。

ただ全体としてはJavaのコードだけではダメでクライアントサイドスクリプトとかイメージのようなスタティックファイルなんかも動的に追加したいとなった場合、どうなんだろう。それ専用のコンテンツローダを作るのだろうか。

アプリケーションサーバによってはサーバ側の設定でやれそうではあるけど。

com.caucho.java.CompileClassNotFound: illegal utf8 encoding at (140)

e-Builder 7.2.x でデバッグサーバを起動しようとして以下のような例外で止まる。 昨日までは動いてたのにな?

警告: com.caucho.java.CompileClassNotFound: illegal utf8 encoding at (140)
com.caucho.java.CompileClassNotFound: illegal utf8 encoding at (140)
    at com.caucho.loader.CompilingLoader.compileBatch(CompilingLoader.java:749)
    at com.caucho.loader.CompilingLoader.make(CompilingLoader.java:353)
    at com.caucho.make.MakeContainer.make(MakeContainer.java:70)
    at com.caucho.loader.DynamicClassLoader.make(DynamicClassLoader.java:1134)
    at com.caucho.loader.EnvironmentClassLoader.scan(EnvironmentClassLoader.java:526)
    at com.caucho.loader.DynamicClassLoader.sendAddLoaderEvent(DynamicClassLoader.java:746)
    at com.caucho.loader.DynamicClassLoader.init(DynamicClassLoader.java:1163)
    at com.caucho.loader.EnvironmentClassLoader.init(EnvironmentClassLoader.java:186)
    at com.caucho.loader.ClassLoaderConfig.init(ClassLoaderConfig.java:156)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.caucho.config.j2ee.PostConstructProgram.inject(PostConstructProgram.java:60)
    at com.caucho.config.type.BeanType.init(BeanType.java:226)
    at com.caucho.config.ConfigContext.configureChildNode(ConfigContext.java:522)
    at com.caucho.config.ConfigContext.configureAttribute(ConfigContext.java:327)
    at com.caucho.config.program.NodeBuilderChildProgram.inject(NodeBuilderChildProgram.java:56)
    at com.caucho.config.program.ContainerProgram.inject(ContainerProgram.java:80)
    at com.caucho.config.program.ConfigProgram.configure(ConfigProgram.java:61)
    at com.caucho.server.deploy.EnvironmentDeployController.configureInstance(EnvironmentDeployController.java:364)
    at com.caucho.server.deploy.EnvironmentDeployController.configureInstance(EnvironmentDeployController.java:55)
    at com.caucho.server.deploy.DeployController.startImpl(DeployController.java:665)
    at com.caucho.server.deploy.StartAutoRedeployManualStrategy.startOnInit(StartAutoRedeployManualStrategy.java:74)
    at com.caucho.server.deploy.DeployController.startOnInit(DeployController.java:549)
    at com.caucho.server.deploy.DeployContainer.start(DeployContainer.java:160)
    at com.caucho.server.webapp.WebAppContainer.start(WebAppContainer.java:659)
    at com.caucho.server.host.Host.start(Host.java:450)
    at com.caucho.server.deploy.DeployController.startImpl(DeployController.java:667)
    at com.caucho.server.deploy.StartAutoRedeployAutoStrategy.startOnInit(StartAutoRedeployAutoStrategy.java:72)
    at com.caucho.server.deploy.DeployController.startOnInit(DeployController.java:549)
    at com.caucho.server.deploy.DeployContainer.start(DeployContainer.java:160)
    at com.caucho.server.host.HostContainer.start(HostContainer.java:484)
    at com.caucho.server.cluster.Server.start(Server.java:1319)
    at com.caucho.server.cluster.Cluster.startServer(Cluster.java:710)
    at com.caucho.server.cluster.ClusterServer.startServer(ClusterServer.java:542)
    at com.caucho.server.resin.Resin.start(Resin.java:703)
    at com.caucho.server.resin.Resin.initMain(Resin.java:1162)
    at com.caucho.server.resin.Resin.main(Resin.java:1365)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at jp.co.intra_mart.bin.server.core.WebApplicationServer.run(WebApplicationServer.java:259)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.CharConversionException: illegal utf8 encoding at (140)
    at com.caucho.vfs.i18n.UTF8Reader.read(UTF8Reader.java:158)
    at com.caucho.vfs.i18n.UTF8Reader.read(UTF8Reader.java:184)
    at com.caucho.vfs.AbstractByteToChar.readChar(AbstractByteToChar.java:153)
    at com.caucho.vfs.AbstractByteToChar.addChar(AbstractByteToChar.java:125)
    at com.caucho.java.JavacErrorParser.parseErrors(JavacErrorParser.java:74)
    at com.caucho.java.ExternalCompiler.compileInt(ExternalCompiler.java:218)
    at com.caucho.java.AbstractJavaCompiler.run(AbstractJavaCompiler.java:102)
    ... 1 more 

デバッグサーバを再構築したりワークスペースを切り替えたりしたけどダメで結局e Builder再インストールしたら直った。