knok のすべての投稿

knok について

I am a Debian Developer and a board member of Free Software Initiative (FSIJ).

Nuro光のルーター(HG8045Q)でDMZからglobal側のIPアドレスを取得する(UPnP)

最近、自宅の回線をNuro光にしました。今までLinuxマシンにPPPoEルーターをやらせていたのですが、それと同等の環境を得るためにDMZへLinuxマシンを置いて処理をやらせるようにしました。

ここで一つ問題なのが、いかにして外部サービスに頼らすglobal IPのアドレスを調べるかです。ルーターはISPから貸与されたHG8045Qであり、管理画面は今どきのJavaScript必須なwebインターフェースです。httpで管理画面をたたいてアドレスを取得するのは面倒そうでした。できれば外部サービスには頼りたくありません。

UPnPのNAT越えについて調べてみた – いろいろな何か :こちらの記事を参考に、UPnPでアドレスを取得する方法を行いました。

まずは記事に習ってM-SEARCHを投げます。Python3用コードに書き直しました。

#!/usr/bin/python3

import socket

M_SEARCH = 'M-SEARCH * HTTP/1.1\r\n'
M_SEARCH += 'MX: 3\r\n'
M_SEARCH += 'HOST: 239.255.255.250:1900\r\n'
M_SEARCH += 'MAN: "ssdp:discover"\r\n'
M_SEARCH += 'ST: upnp:rootdevice\r\n'
M_SEARCH += '\r\n'
M_SEARCH = bytes(M_SEARCH, 'ascii')
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.settimeout(5) # 5秒でタイムアウト
s.bind(('', 1900))
# M-SEARCHをマルチキャストする
s.sendto(M_SEARCH, ('239.255.255.250', 1900))
while True:
try:
response, address = s.recvfrom(8192)
print('from', address)
       print(response.decode('ascii'))
print('=' * 40)
except socket.timeout as e: # タイムアウトしたときの処理
print(e)
break
s.close()

これを実行するとDLNAサーバになれるWindows10マシンたちも反応するのですが、必要なルータ(手で固定IPとして設定した)のレスポンスのみに着目します。

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
DATE: Thu, 14 May 2020 22:12:07 GMT
EXT:
LOCATION: http://192.168.xx.254:49652/49652gatedesc.xml
OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01
01-NLS: 0405f658-xxxx-xxxx-xxxx-e6e487df1fbe
SERVER: Linux/3.10.53-HULK2, UPnP/1.0, Portable SDK for UPnP devices/1.6.18
X-User-Agent: UPnP/1.0 DLNADOC/1.50
ST: urn:schemas-upnp-org:service:Layer3Forwarding:1
USN: uuid:00e0fc37-xxxx-xxxx-xxxx-084F0AC2AED2::urn:schemas-upnp-org:service:Layer3Forwarding:1


LOCATIONに書かれているURLにアクセスしてみます。

 <?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<friendlyName>Huawei IGD</friendlyName>
<manufacturer>Huawei</manufacturer>
<manufacturerURL>www.huawei.com</manufacturerURL>
<modelDescription>Huawei EchoLife Series</modelDescription>
<modelName>Huawei EchoLife Series</modelName>
<modelNumber>Huawei ONT</modelNumber>
<modelURL></modelURL>
(略)
<service>
<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
<controlURL>/upnp/control/WANIPConn1</controlURL>
<eventSubURL>/upnp/control/WANIPConn1</eventSubURL>
<SCPDURL>/gateconnSCPD.xml</SCPDURL>
</service>
(以下略)

参考にした記事ではWANPPPConnection:1を見るようになっていましたが、Nuro光はIPoEでアドレスをもらうためWANIPConnection:1を見るようにすれば良いようです。以下のようなコードでSOAPリクエストを投げ、結果をparseしました。

#!/usr/bin/python3
#-*- coding:utf-8 -*-

import urllib.request, urllib.error, urllib.parse
from bs4 import BeautifulSoup

HOST = '192.168.xx.254'
PORT = 49652
CONTROL = '/upnp/control/WANIPConn1'
URL = 'http://' + HOST + ':' + str(PORT) + CONTROL

SOAP = '''<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
     s:encodingStyle="http://schemas.xmlsoap.org/encoding/">
  <s:Body>
    <m:GetExternalIPAddress xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">
    </m:GetExternalIPAddress>
  </s:Body>
</s:Envelope>
'''
SOAP = bytes(SOAP, 'ascii')

req = urllib.request.Request(URL, data=SOAP)
req.add_header('Content-Type', 'text/xml; charset="utf-8"')
req.add_header('SOAPACTION', '"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"')
#req.add_data(SOAP)

res = urllib.request.urlopen(req)

x = res.read()
x = x.decode('ascii')

soup = BeautifulSoup(x, 'xml')
ex = soup.find_all('NewExternalIPAddress')[0]
ipaddr = ex.text
print(ipaddr)

これで無事グローバスIPアドレスを外部に頼らず取得できるようになりました。これでddnsの更新が行えます。

“Adversarial Policies: Attacking Deep Reinforcement Learning”をざっと読んだ

機械学習で画像分類器をだますAdversarial Exampleは広く知られていますが、強化学習でも同じ問題があるそうです。observation対して摂動を与えることで意図しない挙動をさせることができるそうです。

observationは第三者が直接介在できるものではないのですが、環境を共有するゼロサムゲームにおいて、自身の挙動を介して相手のobservationに狙った摂動を与える、blackbox, model-freeな手法が提案されている(
https://adversarialpolicies.github.io/ )とのことでちょっと論文を読んでみました。

さすがに状況は限定されているようで、環境が高次元であること、デプロイされたエージェントの重みが固定されているという状況で、無制限に相手のポリシーがサンプリングできることが条件のようです。

見た感じ、人間同士のゲームプレイにおけるフェイントに似ているなあという印象を受けました。生成されたadversarial policyに対してfine-tuningはできるものの、それに対してさらなるadvaersarial policyを生成することができるそうで、それを交互に繰り返すことでロバストなポリシーにできるとのことです。

adversarial policyの学習は相手agentのself-playによる学習にかかる時間の3%程度でできてしまうとのことで、adversarial exampleの世界でも攻撃者有利なのは相変わらずのようです。

バーチャル背景を任意のサービスで利用する

webcamにアクセスして、人体を検出し背景画像と合成をするページ
https://knok.github.io/virtbg/ を作りました。TensorFlow.js, BodyPixを使っています。

ページそのものは単にカメラへのアクセスと画像合成だけを行うので、これをオンラインミーティングサービス等で使うためには何かしらの手段で出力をカメラに見せる必要があります。Qiitaの記事として、OBS studioとプラグインを組み焦る方法を書きました。

Windows, Linux, Macそれぞれに対応するプラグインがあるので、それらのプラットフォームで利用できます。Linuxならv4l2loopbackを使います。

ブラウザ->OBS->プラグインという処理パイプラインになるので、これでも若干のオーバーヘッドがあります。Google Meetでカメラを差し替えるChrome拡張として実装した人がいるので、この方法ならオーバーヘッドはより少なく済んでいそうです。私は面倒だったのでOBSに機種依存部分を丸投げしてしまいましたが…その代わり任意のサービスに利用ができます。Jistiでも使えるので次のオンラインセミナーではこれを使うつもりです。

Debian buster上でflatpakのSteamとProtonを動かす

前々からsnap/flatpak,  wine on dockerなど色々な方法でWindows用のゲームをDebianから動かそうと時々試していたのですが、環境をそこそこ汚さずに動作できるようになりました。

flatpak + Steam

flatpakはコンテナを利用したソフトウェア配布ツールです。同様のものにsnapがありますが、flatpakはデスクトップアプリ向けらしいです。flatpak自体はaptでインストールできます。

Steamのインストール、実行は以下のようなコマンドで行います。

flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install com.valvesoftware.Steam
flatpak run com.valvesoftware.Steam

Protonの有効化

以下の記事を参考にしました。

Days of Speed Debian StretchにSteamをインストールしてSteam Play(Proton)でWindowsゲームを遊ぶ

flatpakで入れた場合i386ランタイム等も一緒に入れてくれるので、add-architectureなどをする必要はありません。単純にSteamの設定でベータに参加しProtonを有効化するだけです。

ゲームをインストール

一般的なSteamの操作でWindows向けゲームをインストールします。初回はProtonのダウンロードとインストールが行われます。ゲームによって必要なVC runtime等も必要な場合はゲームの初回起動時に行われます。

簡単に手元で動いたものを列挙しておきます

ファイルの実体が置かれる場所

~/.var/app/com.valvesoftware.Steam 以下に配置されます。mod等を入れるならここを直接いじることになるでしょう。flatpakでSteamを消してもここは残るので不要なら直接rmしましょう。

ToDo/課題

  • ジョイスティックの利用
  • Intel Graphics以外のGPUでの動作確認
  • さらなるゲームの動作確認

追記(2019/9/10)

flathubのリポジトリ追加コマンドを記載しました。

転職活動についての総括

 

以前退職予定エントリーを書きましたが、退職・無職・就職という過程を経てひと段落ついたので、総括をしてみようと思います。

いつから転職活動を行っていたか

実のところ、3年ぐらい前(2015年頃)から転職活動を始めていました。なかなか思うような結果が出なかったのですが、2017年度になって早期退職制度の対象者となり、良い機会だったので応募し、受理されて無事円満退職となりました。

一応、転職以外の道として単純に給与あるいはそれ以外の何かで収入を増やす手段も検討し、そういったことを当時の上長にも相談したりということは行いましたが、会社の給与体系から逸脱するようなことはできませんでした。

どのような手段を用いたか

先の退職エントリーをSNSで広める以外に、以下の手段を用いました。

  • エージェントの利用
  • 転職サイトの利用

エージェントについて

転職を考え始めた時期に、転職エージェントのほうから声がかかりました。いくつかのアドバイスを得ることができ、個人的には有用でした。特に職務経歴書の書き方は非常に参考になりました。

転職サイトの利用

転職ドラフトに登録し、何度かドラフトに参加しました。登録した理由は、たまたま見かけたPR記事が知人だったからです。

いくつかの指名を得ることはできましたが、最終的にマッチングがうまくいかなかったかなあ、という感じです。一つ残念だったのは、「提示した年俸の最低90%を指名企業は提示する」というルールが守られていなかったことです。この点については運営に直接伝えてはいます。

LinkedIn

かなり前からLinkedInのアカウントは持っていました。特に外資企業からの連絡はLinkedIn経由でそこそこありましたが、resumeを送ってその後音沙汰なし、ということも多かったです。

SNSでの退職エントリー公開について

自分が予想していたよりは大きな反響がありました。10社ぐらいはコンタクトがありました。それでもやはりマッチングには苦労し、最終的に今の会社に雇用されました。

エントリーはblogで、発信は主にTwitterで行いましたが、連絡手段としてはFacebook経由が最も多く、次いでメール、Twitterという感じでした。転職活動をするにあたってFacebookアカウントはあったほうが良いのかなと思います。

前職を辞めるにあたって

早期退職制度の申請に関しては非常にスムーズでした。上司たちも「会社が用意した正当な手段であり行使は自由だ」といって下さり、実際に円満退社できたことには感謝しています。

転職支援制度の利用

早期退職制度の一環として、転職コンサルティング会社の1年間分の提供があり、一応使ってはみました。

私を担当したコンサルタントの方はあまり自分の関心のある分野には明るくなかったようでしたが、それでもいくつか見繕ってはくれました。私の職務経歴書を見たうえで「これぐらいの年収が適切だろう」というものを提示してくれたので、客観的な市場価値を知ることができた(そしてやはり前職の給与は安かった)のはよかったと思います。

新しい職場について

最初の方では軽く触れましたが、2018年4月16日付けでロボット投信株式会社に入社し、働いております。

現状は主にR&Dを担当しており、自然言語処理を中心としています。投資、ファイナンスに関する研究発表は人工知能学会、言語処理学会でも割となされており、それらの再現実験や、機械学習の実サービスへの応用の模索といったことを行っています。

その兼ね合いもあり、6月に鹿児島で開催された人工知能学会全国大会にも業務として参加しました。FLOSS活動にも理解が深く、7月~8月に開催されたDebConf18も業務扱いで参加させてもらうことができました。

ロボット投信株式会社ではエンジニアも募集しています。Wantedlyに募集ページがありますが、私個人へのコンタクトも受け付けております。もし興味のある方がいらっしゃいましたらご一報ください。

 

2018年のエイプリルフール

自分の観測範囲で見かけたものをまとめてみます。ほかにFLOSS関連でこんなのがあった、という話があれば追加します。

Free Software Foundation announces crowdfunding campaign to buy Facebook — Free Software Foundation

FSFがFacebookを買収するためにクラウドファンディングを始めた、というネタ。ところでFacebookはGnuPGに寄付をしています。

Bug#894551: ITP: fascism — Exhaustive exploration of Fascist theory and practice

ファシズムをDebianパッケージ化する提案です。過去にもrootkitのITPなど、エイプリルフールネタはありました。

退職予定エントリ

「俺は仕事をやめるぞー!ジョジョーーッ!」

一度は書いてみたかったセリフなのですが、まだ確定ではありません。オリジナルは荒木飛呂彦作の「ジョジョの奇妙な冒険」第一部、ディオのセリフです。

経歴について

職務経歴書を公開します。

2017/12現在の状況

今年から早期退職制度 の対象者となったので、周囲に相談しつつ申請をしたという状況です。承認されれば今年度一杯をもって退職となります。

理由

一言でいえば「待遇に不満がある」のが理由です。調査会社による年齢ごとの年収調査によると、残業を含めた上での額面での現在の年収に対し、平均から-200、最低値と比較しても-100という状態です。

残業に関しては正直なところ「生活残業」状態であり、限度いっぱい働いているような状況です。2年ほど前から私生活上どうしても収入が必要になってしまったのですが、貯蓄もできずぎりぎりの状態を続けています。一方で心身の健康上今の生活を継続するのも厳しい、このままで健康を取り戻すことはできそうにない、ということで申請の決意をしました。

 これまでの経験

1990年台後半当初は名古屋で働いていました。当時はインターネットの商業展開が始まった時期で、基本的にDebianでサーバを立てたり、CGIベースでプログラムを組んだりといったことを行っていました。全文検索システムにfreeWAISやNamazuを使うこともありました。当時はFLOSS活動が業務と直結していて、この時代は業務時間内のコミットも自由にできていました。この頃はDebian Projectは2000年問題に対して積極的な取り組みをしており、私自身も2000年をむかえる時にサーバーが無事年を越せるか現場待機していました。一人で。業務で日をまたいだことは、生涯を通してこの日だけです。仕事で徹夜などをしたことはありません。

21世紀に入ったところで、東京へ転勤になりました。東京での仕事はこれまでとは大きく変わりました。当初は電子ペーパー上にレンダリングする組版システムの担当ということだったのですが、2年ほどしてまったく違うプロジェクトにかわり、それ以後半年から2年程度という短いスパンで大きく違うプロジェクトに回される、というサイクルを繰り返しています。

直近では、機械学習を主題とした課題に取り組んでいます。画像処理・自然言語処理が中心です。ここ2年ぐらいは学生の頃よりたくさん論文を読んでいます。オープンアクセス万歳。

現職の良いところ

2000年代前半まではかなり自由にやらせてもらえました。Linux協会の活動も業務の一環として行っていましたし、FLOSS活動にも特に制限はありませんでした。

会社も安定はしています。これまでに働いていて、赤字だった年度は1回だけでした。ただ、主力である印刷に関しては斜陽であり、いかに新しい事業に活路を見出すかというのは常に課題です。

私が携わった範囲では、新しい技術に触れることができていました。これは個人的に環境として恵まれていたと思っています。必ずしも全社的にそういう傾向があるわけではありません。基本的にはオールドファッションな社風です。

労働環境も世間的に見ればかなりよい方でしょう。もっとも、事業部によっては激務であるとは聞いています。その代わりに残業代はきちんと出ます。

 自己アピール

ソフトウェアについて、幅広い範囲を取り組んできました。半年から2年で内容が変わりながらもなんとか追いついてそれなりの成果を出すことができていたと自分では思っています。

一方で長年取り組んできたのはDebian ProjectをはじめとするFLOSS活動です。アクティブでない年もありましたが、なんとか今も継続してやっています。最近ではuim回りでいろいろお手伝いをしています。このブログをホスティングしているマシンも20年以上Debian hammあたりからアップグレードを重ねてきています。さすがにいい加減i386は厳しいなという状況で、amd64への移行をいずれどこかでやる必要があるなと感じつつ数年経過しています。

私の職務経歴書、このブログ、GitHub, Qiita等を見て人材として興味のある方がいれば、ぜひメール、SNS(Twitter, Facebook) 等でご連絡ください。

 

GANsやOpenCVをいじっている

ここのところ、画像処理関連をやってみています。

以前pix2pixをいじっていましたが、そこでも使われているGANs(Generative Adverarial Networks)という技術を、なにかしら自分の趣味の範囲で利用できないかなあと試してみています。

初期に提案されたDCGANは非常に衝撃的だったのですが、いかんせんハイパーパラメータのチューニングがシビアでした。学習がうまくいかないとmode collapseという現象を起こし、まったく意味不明な画像しか生成できなくなります。

この辺りの数理的理解が進んできて、mode collapseを起こしにくい新しい手法が提案されています。

chainer-gan-libという、Chainer開発元であるPreferred Networkが複数種類のGANsを実装、公開しています。主にこちらを使って画像生成を試してみています。

ただ、やはり少ない画像数でこれを行うことは難しいなあというのが実際やってみての感触です。

GANsでは生成器と識別器、2つのネットワークを交互に学習します。生成器はある分布に従う潜在変数の存在を仮定し、そこからサンプリングした乱数から画像を生成します。識別器は、生成器が生成した画像群を負例、訓練用に用意した画像を正例としてそれらを正しく分類するようなネットワークです。

生成器と識別器を交互に学習させることで、生成器は識別器の正例群が持つ画像の特徴を捉えた画像を生成できるようになる、というのがGANsの大まかな仕組みです。生成器と識別器はそれぞれ反対方向の目的関数に向かって最適化されるので、最終的にお互いの訓練誤差が均衡した状態が理想となります。

正例の画像があまりに少ないと、識別器の損失(誤差)がかなり小さな値にとどまってしまい、生成器は正例の画像をほぼそのまま覚えてしまうようです。つまるところ、「十分な数のデータがないと特徴を正しく捉えられない」というある種当たり前の結論に至りました。

人間だったら少ないサンプルからそれっぽいことが学習できるんですけどねえ…と思ったところでGANsの転移学習はできないのか、ということをこれを書きながら思いました。

何かしらの画像をうまく生成できるだけのモデルを予め学習させておき、それをベースにfine tuningすればもう少しマシな結果が出るのでは、という予想です。

これは一度試して見る価値はあるかもしれませんね…そのモデルを学習させるためのデータをどうやって用意するか、という課題はありますけど。

uim 1:1.8.6+gh20161003.0.d63dadd-6

unstableのuimを更新しました。以下の2つのRC bugを修正してあります。

前者の問題は、いくつかのパッケージ統合作業を行った時に、libuim-devのドキュメントをsymlinkに変えたことがトリガで発生した問題です。postinstで以下の処理を追加しました。これにより、symlinkが必要に応じて生成されます。

dpkg-maintscript-helper dir_to_symlink \
                /usr/share/doc/libuim-dev /usr/share/doc/libuim8 1:1.8.6+gh20161003.0.d63dadd-2.1 -- "$@"

後者の問題は 、uimバイナリパッケージに/var/lib/uimのみを所属させていたのがトリガです。パッケージ統合作業の時にlibuim-dataを廃止したのですが、このパッケージのpostrmではpurge時に”rmdir –ignore-fail-on-non-empty”を呼び出して/var/lib/uimを削除しようとします。uimパッケージに所属しているのはディレクトリのみなので、ここで削除されてしまうというわけです。

こちらの対処としては、/var/lib/uim/READMEを用意してディレクトリを空にしないという方向で解決しました。同様の処置をしているパッケージは他にもあるので、対処としては間違ってないと思います。多分。

テキスト分類をDNNでやってみて思うところ

以前このような記事を書きました。

複数の単語から構成される文章を、Bag-of-Wordsと対応する単語分散ベクトルで表現し、特徴ベクトルの最大値のみを抽出する、という感じの手法です。

これの実装を書いた時はまだあんまり機械学習のことがよくわかっていなく(今もよくわかっていませんが)、それでも実験的、感覚的に「この手法は特に単語が増えると精度でないだろうな」と思っていました。

なので、その後畳み込みネットワークベースの手法を試しています。他の人が書いたChainer実装は既にあったので、自分はそれの最上層をSPP-Netに置き換えただけのものを試しています。

基本的に、こちらのほうが特徴量をより多く捉えているはず(層の数とか種類とかから類推)なので、きっと性能は高いと思います(未検証)。そこは同じテータセットを使ってちゃんと試したいところですが、GPUの空き時間ができたらということで…

そんなわけでRecurrent CNN(RCNNはRegions with CNNと混同しやすい略称なのでこう記述します)は「自分も論文だけ見て実装することはできたので満足。だけど手法としてはいまいちっぽいよね」という気分でいました。

ふと先日この記事が目に飛び込んできました。

ちょっと過大に扱われてしまったのではないかと思い、この記事を書いています。

分類結果の出力

自分の実装では評価時に最終出力として、全層結合層(Fully Connection layer)の値を生のまま出しています。実際にはこれにソフトマックス関数をかませて0〜1の確率値に整えるべきなのですが、そこをちょっとさぼっています。

ともかく、ソフトマックス関数で計算される分類タスクの出力は、全ラベルそれぞれの確率の合計が1になるよう調整されます。

Recurrent CNNでは分散表現の実数をそのまま加算するため、全体としては大きな値になりがちでです。その辺りの正規化が皆無なので、おそらく文章が長くなるほどあやしい挙動を示すでしょう。

分散表現獲得

また、分散表現の獲得もあまりよろしくない作りになっていると思います。乱数を初期値とし、逆誤差伝搬で各文字の分散表現を獲得しています。

十分なデータ量がないと、適切な分散表現は獲得できないと思います。代わりに、例えば一般的な表現が多数出現するデータ量の多いコーパス(Wikipediaの記事、新聞記事など)から、word2vec等で獲得した分散表現を初期値に設定してやる、といったことで性能が向上する可能性があります。

2017/8/30 追記: 今回のケースだとWikipediaよりも2chの各種書き込み、Twitterのツイートから分散表現を事前訓練したほうが良い気がしてきました。

「その他」というラベルの扱いの難しさ

MNIST, ImageNet, CIFAR10等誰もが入手できるデータセットは非常に限られた分類のデータしかありません。それらを識別するモデルを用意したとして、まったく関係ないデータを与えると、識別器は無理やり何かしらの値を出力します。運が良ければ何かしらの要素が似ているものへの確率が高く出ますが、最悪まったく関係ないラベルだと推論してしまいます。

これを回避するために、たとえば雑多なデータをたくさん用意して「その他」ラベルを作るという解決方法がありますが、これも一筋縄ではいきません。

今年2017年の人工知能学会でクックパッドが発表した論文に、この過大に取り組んだ話が掲載されています。

「料理・非料理判別問題」というタスクを設定しています。単純に2クラスに分けると全く関係ない画像が料理判定されるケースについて言及があります。

彼らはあえてより多くのクラスに分類した時、そうで無い時で分類精度を評価しています。以下論文の引用になります。

F 値が最も高いモデルは料理・非料理ともに多クラス化したものだが, 提供するサービスの性質上, 我々は料理クラスは単一クラスで非料理クラスは多クラス化したものを採用している.

客観的な指標(F-measure)では料理、非料理それぞれ多クラス分類した方が精度は高かったが、サービスの特性上適合率(precision)よりも再現率(recall)が高い手法を採択したとのことです。

分類対象がテキストであったとしても、同様の傾向が出るであろうことは予想されます(CNNベースなら画像と扱いとしては同じため)。

つまるところ、分類クラスを増やすことで「そのクラス固有の特徴が分類器(の中間層)で獲得できる」ということであり、それを雑多に「その他」にまとめてしまうと特徴にバリエーションがありすぎて、かえってうまく特徴を捉えられないことが起きうるというわけです。

Conclusion

結局何がいいたかったかというと、

  • Recurrent CNNは感触としてあまり高い精度出ない
    • 単語分散表現の初期値にword2vecを使えば精度は上がると予想
    • 多分CNNベースの方が良い結果が出る
      • SPP-Netを使ったコードを書いたので、可変長データも扱えるはず
  • 単純な2値分類は危険
    • 問答無用でどちらかのクラスに分類されてしまう
    • 他クラスに分けることで精度を上げられる

といったところです。さすがにはてなブックマークのコメント100文字(http://b.hatena.ne.jp/entry/344063592/comment/knok)では伝えきれないので、記事にしてみました。

おまけ

こちらの記事でRecurrent Highway Networksという、highway networksをRNNに適用する論文の紹介資料があります。このページから直接speakerdeckへのリンクにとぼうとすると404になってしまうので、このページの埋め込み資料を見てください。元論文は以下のようです。

ブックマークコメントについて

こんな感じで修正していったように記憶しています。

  • RCNNの実装書いた本人です。2価分類はそれぞれの選択肢の確立が1になるような出力になるので、関係ない人物何人かも含めて訓練した方がもうちょっとマシな結果が出るかもしれません
  • RCNNの実装書いた本人です。2価分類はそれぞれの選択肢の確立が1になるような出力になるので、関係ない人物何人かも含めて訓練した方がもうちょっとマシな結果が出るかもしれません/多値分類でも合計は1
  • RCNNの実装書いた本人です。分類問題はすべての選択肢の確率合計が1になるような出力になるので、関係ない人物何人かも含めて訓練した方がもうちょっと良い推論結果が出るかもしれません/追記しきれないので誤字修正