Quantcast
Channel: ALBERT Official Blog
Viewing all 191 articles
Browse latest View live

小学校から「将来の夢」についてお手紙をいただきました。

$
0
0
こんにちは、ALBERT広報の鈴木です。

先日、小学校の生徒さんから当社宛にお手紙をいただきました。学校の「総合的な学習の時間」に将来の夢について学んでおり、「データサイエンティスト」という仕事の楽しいところや大変なところ、またどんな人がデータサイエンティストに向いているのかを知りたい、というものでした。

お手紙には当社のデータサイエンティスト(リサーチャー)から返事を書かせていただきましたが、今回このような貴重な機会をいただくことができ、データを扱う仕事に興味のある方、ALBERTに興味があるという方にもぜひ読んでもらいたいと思い、ご紹介させていただきます。

◆いただいたお手紙
授業で将来の夢について学ぶ時間があり、小学校6年生の方がデータサイエンティストについて知りたいと今回ALBERTに連絡をくれました。



◆質問へのお返事
こちらのお手紙をいただき、当社データサイエンティストでリサーチャーの山内から、「データサイエンティストの楽しいところ」「大変なところ」「どんな人がデータサイエンティストに向いていると思うか」について、以下のように回答しました。


————————————-

○○○○さん、はじめまして。
株式会社ALBERT(アルベルト)先進技術部の⼭内隆太郎といいます。今回はわたしのほうから○○さんの質問にお答えできればと思います。

○○さんのお⼿紙を読み終えたとき、最初に思ったのが「⾃分が返事を書いてよいのだろうか」ということでした。理由はふたつ。ひとつは、わたしの業務はいわゆる「データ分析」とは少し違うということ。もうひとつは、⾃分は⽬指してデータサイエンティストになったわけではないということです。ですから、データサイエンティスト志望の⼩学⽣に対して、なにか役に⽴つことを⾔えるだろうかと少し悩みました。

しかし考えてみれば、○○さんが⼤学を卒業して働きはじめるようになるのは早くて10年後なわけです(もちろん⾶び級するということも考えられますけれど)。わたしの記憶にある10 年前の世界と現在の状況がまったく違っていることを思えば、おそらく10年後の状況もまったく違ったものになっているでしょう。そういう意味では、いまここで誰がどのような返答を書いたところで、10 年後のデータサイエンティスト志望者に対する⾔葉としては、同じように的外れなものになるような気がします。それならば、あくまで現在のデータサイエンティストのひとつの実例として書く限りでは、⾃分が書いてもよいのかもしれない、そう思って筆を取った次第です。したがって、以下に書くことは 2021 年現在における、ひとりの個⼈の考えです。それを念頭に置いたうえで、参考にしたりしなかったりして
もらえると幸いです。

そういうわけなので、ご質問に答える前に、まずは簡単に⾃⼰紹介させてください。わたしはいま28 歳で、アルベルトで働きはじめて5 年⽬になります。⼤学での専攻は哲学で、ウィトゲンシュタインという哲学者について研究(といっても⼤したものではないのですが)していました。哲学って⾔葉を聞いたことがあるでしょうか?⼀⾔で説明するのは難しいですが、そうですね、真理とか意味とかについて延々と考える、役に⽴たない学問の筆頭みたいなものです(半分冗談ですよ)。で、哲学専攻の学⽣がなぜいまデータサイエンスをやっているのかといえば、きっかけは些細なもので、学⽣時代に参加した読書会(みんなで集まって同じ本を読むという変なイベントです)で出会った アルベルトの社員に、「うちでアルバイトをしませんか」と誘われたのが始まりです。当時その⼈は「ディープラーニング」について多少なりとも知識のある⼈を探していて、わたしはその条件に合致したというわけでした。

ディープラーニングというのは、すでに名前を聞いたことはあるかと思いますが、多層ニューラルネットワークを利⽤した⼈⼯知能技術です。2010 年代に急速に発展し、今では画像認識をはじめ⾃然⾔語処理やら⾃然科学やら多種多様な⽬的に応⽤されています。わたしがディープラーニングを知ったのはたしか 2014 年のことで、興味本位で数学科の講義を受けていたときでした。その講義でディープラーニングの基本的な考え⽅を教わり、「これはたいへん⾯⽩い技術だ」と感動したわたしは、個⼈的に簡単な⼈⼯知能を作って遊ぶようになりました。それがアルベルトでのアルバイトに(読書会を介して)繋がったというわけです。縁というのは不思議なものだと思います。

そのころのアルベルトは社員数30 ⼈くらいの⼩さな会社で、ディープラーニングの専⾨家もほとんどいなかったので、何⼈かで⼿探りで最新の研究論⽂を読み、プログラムを書いて実験し、ということをやっていました。わたしもそこに投⼊され、論⽂を読んだり⼈⼯知能を実装したりするようになったのですが、これがなかなか⾯⽩い。毎⽇のように新しい論⽂が発表され、いままで出来なかったことができるようになっていく。しかもちょっとプログラムが書ければ⾃分でも試してみることができる。⼤学を出たあと何をして⽣きていくのかなんてまったく考えていなかったわたしですが(哲学なんぞをやってたくらいですからね)、案外こういうことを仕事にするのもいいんじゃないかと思うようになりました。そしていつの間にかアルベルトに就職し、気づけば4 年以上経っていたというわけです。

そういう経緯で⼊社した⼈間なので、わたしの仕事はもっぱらディープラーニングに関わることでした。アルベルトには現在200 ⼈以上のデータサイエンティストが在籍しており、データ分析基盤の構築や収集したデータの統計解析などいくつものプロジェクトが進⾏していますが、そこで使われる技術や考え⽅はさまざまで、ディープラーニングはその⼀部にすぎません。また技術以外にも、どのようなお客さんを相⼿にするかとか、所属している部署などによっても、業務の在り⽅は変わってきます。とくにわたしは、最近ではお客さんのデータを解析する仕事から少し離れて、新しい⼈⼯知能アルゴリズムを作る仕事をしており(あまり順調ではないのですけど)、さらに少数派です。テーマは「三次元空間の意味と構造をどうやって⼈⼯知能に教えるか」というもので、膨⼤なデータの中から規則を⾒
つけたり予測をしたりというのがデータ分析の中⼼的内容だとするなら、ちょっと変わったことをしていることになります。この返事を書くのを少しためらったのはそういう理由からです。ですから、これから書く回答があまり⼀般的なものだと思われないように、回答者のバックグラウンドを開⽰しておくことにしました。もっと別の⼈の意⾒が聞きたい!ということであればアルベルトや他の会社にメールを出してみるとよいかもしれません。

将来を考える⼩学⽣からのメールということであれば、わりと返事が返ってくるのではないかと思います。返ってこなかったとすればそこはたぶんろくな会社ではないです。
たいへん前置きが⻑くなりましたが、ご質問に答えていきたいと思います。


① データサイエンティストで楽しいところは何ですか。
わたしはディープラーニングという考え⽅そのものがけっこう好きで、それに関わっていること⾃体が楽しいです。どこが好きかということを詳しく説明するのは難しいのですが、ざっくりと⾔うと、ディープラーニングについて知ることで⼈間の認知の仕組みについても知ることができる(気がする)ということでしょうか。わたしは⼦供のころから⼈間の知能や意識について関⼼があって、哲学を勉強したのもその延⻑でした。そういう意味では、昔から気になっていたことを紆余曲折経ながら今でも考えていることになります。⾃分の考えたいことを考えるというのは楽しいことです。これはまあ、あらゆる仕事に⾔える話でしょうが。

また実際に⼈⼯知能を作って学習させるのも楽しいです。ディープラーニングやデータ分析のためにはコンピュータをうまく利⽤する必要があります。⾼速なコンピュータを準備し、効率のよいプログラムを書かねばなりません。そこにはパズル的な⾯⽩さがあると思っています。綺麗なプログラムが書けると満⾜ですし、また、そうして苦労して実装した⼈⼯知能が想定通りに機能すると「してやったり」という気持ちになります。もちろんうまくいかない場合もあって、その場合は「なにくそ」となります。それはそれで楽しいです。

ところでアルベルトがなぜデータ分析や⼈⼯知能開発をやっているのかといえば、お客さんの抱える課題を解決し、それによって代価を得るためです。最近では少なくなりましたが、わたしもお客さんから要望を聞き、議論して、どのような⽅法で問題を解決できるか考えるという、コンサルティング的な仕事をすることがあります。課題を理解し、⼿持ちの技術でどうやって解決できるか整理し、具体的なアルゴリズムに落とし込む、これ⾃体なかなか楽しい仕事ですし、それによってお客さんが満⾜してくださったり、⾃分の作った⼈⼯知能が実際に世の中で使われるようなったりするのは、嬉しいことだと感じます。


② データサイエンティストで⼤変なところやつらいところは何ですか。
これはたぶんわたし以外のデータサイエンティストも同じではないかと思うのですが、作った⼈⼯知能やデータ分析システムが想定通りに機能しないと⼤変です。⼈⼯知能はプログラムを書けば出来上がるというものではなく、たくさんのデータで学習させて初めて動くようになるものです。ところが、どんなデータでもさばける万能な⼈⼯知能というものは存在せず(「汎⽤⼈⼯知能」と呼ばれる概念で、いまだに研究段階です)、解決したい課題やデータに合わせて⼀つ⼀つ設計してやる必要があります。しかも、実際に使い物になるかどうかは、作って動かしてみるまでは分かりません。⼈⼯知能開発やデータ分析にはそのような予測不可能性がつきもので、限られた期間の中でプロジェクトを遂⾏するとなるとかなりのプレッシャーがかかります。

またデータ分析業界は⾮常に移り変わりの速い領域です。数年前に登場した新⼿法がいまでは時代遅れで誰も使っていないなんてことがままあります。技術の進歩に遅れず付いていくためには、⽇々新しい技術や、あるいはそれらを理解するための基礎的な概念を勉強し続ける必要があります。すべてを理解することはとてもできないので、勉強する対象を選ぶ必要がありますが、⾃分の興味と社会的需要の間でバランスを取りながらやっていかねばなりません。とくにわたしの部署では研究開発をやっていますので、5年後を⾒据えてなにを勉強しなにを研究すべきか、いつも悩みながら働いています。


③ データサイエンティストはどんな⼈に向いていますか。
これはとても答えるのが難しいというか、責任を感じる質問です。ディープラーニングという狭い分野の中でさえ、ここ5年で求められる⼈物像は変わった感じがしますし、10 年後どうなっているかは想像がつきません。なのであまり真に受けずに読んでください。まずデータサイエンスのいずれかの分野が好きであるということは重要だと思います。○○さんは「機械やAI、データ分析が好き」だと書かれていますから、その点では適性があるのではないでしょうか。ただ「好き」とひとことで⾔っても内実はいろいろで、個⼈的には「その対象に⻑時間関わっていても苦しくならない」という意味で好きであることが⼤切なのではないかと感じています。上で述べたように、データサイエンスを仕事にするということはデータサイエンスの進歩についていくということでもあり、そのためには継続的
に勉強を続けていかねばならないからです。たまに⾷べると美味しいお菓⼦であっても、毎⽇⾷べる主⾷にすることは出来ない場合があります。データサイエンティストに向いている⼈とは「データサイエンスを主⾷にできる⼈」なのではないか、というのがわたしの考えです。

それから、⾃分の考えを正確に他者に伝えられる⼈でしょうか。⼈⼯知能の研究開発にせよ、データ分析の成果をお客さんに納品するときにせよ、⾃分がどのように考えどのような⼿法を⽤いたか、そしてその結果はいかなるものであったか、その妥当性を他者に納得してもらわなければ、どれだけ優れた分析をしたところで意味がありません。いずれAI に置き換えられる⽇が来るのかもしれませんが、少なくとも現在の社会を動かしているのは⼈間なのです。データ分析の価値というのも、それがどれだけの⼈に理解され、意志決定に影響を及ぼしたかによって測られるべきでしょう。研究だって同じです。昔の偉い学者というものはだいたいみな⽂章が上⼿いのですが、そのことはきっと彼らの業績と無関係ではないでしょう。

どうも⼀般論的な回答になってしまいました。もう少し具体的な⼈物像を出せればと考えていたのですが、同僚たちの顔を思い浮かべてみても、共通する要素というのはあまり⾒当たりません。⼀定⽔準の学⼒があり、好奇⼼旺盛で、考えることが苦ではない。そのくらいでしょうか。

以上、わたしの狭く短い経験から、書けるだけのことを書いてみました。○○さんが将来のことを考えるうえで、ほんの少しでも参考になったならと思います。
それでは受験勉強(もうそろそろ本番でしょうか?)頑張ってください。お元気で。


株式会社ALBERT 先進技術部
⼭内 隆太郎
————————————-


いかがだったでしょうか。
データサイエンティストとはどんな仕事なのか、どのような人が向いているのかについて、そしてALBERTの雰囲気を少しでも知っていただく機会になれば幸いです。

ALBERTは日本屈指のデータサイエンスカンパニーとして、データサイエンティストの積極的な採用を行っています。また、データサイエンスやAIにまつわる講座の開催、AI、データ分析、研究開発の支援を実施しています。

・データサイエンティストの採用はこちら
・データサイエンスやAIにまつわる講座の開催情報はこちら
・AI、データ分析、研究開発支援のご相談はこちら

The post 小学校から「将来の夢」についてお手紙をいただきました。 first appeared on ALBERT Official Blog.


QT-Optの紹介とオフライン経験データに関する実験

$
0
0

はじめに

こんにちは、ストラテジックアライアンス部データアナリストの野島です。

今回は、Kalashnikov et al. の論文「QT-Opt: Scalable Deep Reinforcement Learning for Vision-Based Robotic Manipulation」 [1]について紹介します。この論文では、深層強化学習手法QT-Optを提案し、ロボットアームの把持で96%という高い把持成功率を達成しています。同じ問題を扱った先行研究Levine et. al. [2] の手法では把持成功率は78%となっており、20%近く成功率が向上しています。また、QT-Optでは、過去の経験データ(オフライン経験データ)を用いた学習により、Levine et. al. の手法と比較して、より少ない把持試行によるデータで成功率を向上させています。

最初にロボットへの期待と強化学習について概観したのち、QT-Optの論文、そして関連して行ったオフライン経験データに関する実験についても紹介していきます。

ロボットへの期待

人手不足が社会問題となっている昨今、様々な業界においてロボットの導入による自動化が注目を集めています。以前から、工場など製造業の現場では組み立てなどで産業用ロボットが活躍しており、製造業でのロボット活用は今後も高い需要が見込まれています。また、ロボットは私たちの生活においても、身近な存在になりつつあります。店舗の受付ロボットや、家庭でお掃除ロボットを利用したことがあるという読者の方も多いのではないでしょうか。ALBERTでもそういったロボット技術の需要を見越して、ロボットの把持や、ロボット自体に空間や物体を認識させる研究を進めています。

この記事では、これらの需要の中でもロボットの把持を取り上げます。把持は工場などでロボットが部品の移動や組み立てを行うときに、最も基本的な動作の一つです。また、私たちの身近で動作するロボットにも把持能力があれば、散らかった部屋での収納といったより複雑なタスクをロボットに任せることができるようになるでしょう。

さて、ロボットによる把持と一口にいっても、あらかじめ決まった物体だけを把持できればいいのか、それとも多種多様な物体に対して把持を行う必要があるのかでその難しさは変わってきます。後者の意味での把持をロボットが行うことができれば、ロボットの活躍の場はより広がっていくはずです。QT-Optの論文では、こうした多種多様な物体にも通用する把持能力の獲得に対して、強化学習によるアプローチを提案しています。

強化学習とロボット

QT-Optの論文の紹介に入る前に、ここでは、強化学習について簡単にまとめます。

強化学習とは

一言でまとめてしまうと、強化学習は、ある目標の達成に向けて、周囲の状況に応じた最適な行動方法を学習する機械学習の一分野です。と言っても、少し分かりにくいので、ゲームを例に強化学習を応用することで何ができるようになるかを説明します。

キャラクターを操作して、ゲーム終了時に獲得したトータルのポイントを競うゲームを考えてみます。ゲームの進行中にはプラスポイントをもらえるアイテムや、ぶつかるとマイナスポイントとなる障害物があるとしましょう。このゲームでの目標はもちろん、より高いトータルポイントを稼ぐことです。そのためには、できるだけアイテムは獲得しつつ、障害物は避けていく必要があります。アイテムと障害物の位置関係によっては、アイテムを諦めたり、ポイントがマイナスになっても障害物にあたる戦略が必要になるかもしれません。強化学習を用いることで、複雑にもなり得る最適なプレイ戦略を学習することができます。

強化学習の枠組み

前節では、機械学習分野における強化学習の位置づけとゲームへの応用を紹介しました。後の説明のため、ここでは強化学習の枠組みをもう少しフォーマルにまとめます。

強化学習では、ゲームの例でキャラクターにあたる操作対象を「エージェント」と呼び、「行動」選択の方法を学習します。ゲームでは、キャラクターはゲームの世界にいて、キャラクターをとりまく状況に合わせて操作を行っていきます。同じように、エージェントはある「環境」にいるとして、環境の「状態」を観測してから行動を選択します。エージェントの行動により状態が変化することもあり、状態の観測と行動選択を逐次的に繰り返していくという設定を強化学習では扱います。

次に、行動の適切さの指標として、強化学習では「報酬」と呼ばれるスカラー値を用います。報酬は行動の度に発生し、報酬の累積値を高める行動選択を強化学習では学習します。報酬は問題ごとに個別に設計する必要があり、ゲームの例ではポイントが報酬にあたります。

探索と学習

では、エージェントの行動をどのような方法で最適化していくのでしょうか。ここでは、多くの強化学習の手法に見られる「探索」によって得られたデータによる最適化について説明します。

強化学習では、教師付き学習と異なり、最初から学習のためのデータがあるわけではなく、環境の中でエージェントが自ら行動することで経験データを集めます。ここで、経験データとは、行動とその行動前後の状態、そしてその時に得られた報酬の組をさします。この経験データを集めるステップは「探索」と呼ばれ、こうして集めた経験データにより行動を最適化、すなわち「学習」を行っていきます。人間が何度もゲームをプレイして、その経験をもとに上達していくことを想像すると分かりやすいと思います。

強化学習の利点

ロボットアームで多種多様な物体の把持を行うときを例に、強化学習の利点を考えてみます。強化学習を用いない場合、把持対象の認識プログラムと把持対象ごとの動作プログラムを組み合わせて把持を実現するというのが一つのやり方です。こうした把持設計では、細かなパラメータの調整を伴うプログラムを複数作成することになり、個別のケースごとに煩雑な作業が必要となります。一方、強化学習を用いる場合、把持対象の認識(状態の観測)とロボットアームの動作(行動)を逐次的に行うことで把持を実現します。把持対象の認識と把持動作をまとめて強化学習に任せてしまうことができるため、それぞれ別個に設計するよりも最適な把持動作を期待できます。さらに、認識を何度も繰り返すため、想定外の状態にも対応可能な把持動作が期待されます。

強化学習の課題

強化学習の課題についても取り上げておきましょう。ここでは特に、ロボットに応用する際の課題を取り上げます。

強化学習ではエージェントの探索により集めた経験データで学習することに触れましたが、ロボット実機での探索には次のような問題があります。まず、探索には非常に時間がかかるという点です。一般に、強化学習では、満足のいく能力を持ったエージェントを学習するために膨大な経験データが必要となります。例えば、DQNと呼ばれる強化学習手法を提案した論文[3]では、Atariのゲームをプレイするエージェントを学習するのに5,000,000個程度の経験データを用いています。ゲームでは、高速にプレイするためのカスタマイズで探索にかかる時間は短縮できますが、例えばロボットアームによる把持では、一回の把持試行に数秒から数十秒かかってしまいます。さらに、パラメータチューニングのため何度か学習をやり直すことを考えると、強化学習の採用を躊躇してしまうほどの時間が探索には必要となります。また、何度も実機を動かす場合、探索の間にロボットが故障してしまう可能性が高く、ロボット実機による強化学習を困難にしています。

QT-Opt: Scalable Deep Reinforcement Learning for Vision-Based Robotic Manipulation

強化学習の課題を踏まえたうえで、ここからは、本題の一つ、Dmitry Kalashnikov et. al. の論文「QT-Opt: Scalable Deep Reinforcement Learning for Vision-Based Robotic Manipulation」[1]を紹介していきます。

論文の概要

前述したように、この論文では、ロボットアームによる多種多様な物体の把持を目指し、QT-Optと呼ばれる深層強化学習の手法を提案しています。

ロボットアームに強化学習を応用する際に問題となるのが、前節で触れた探索にまつわるコストです。QT-Optでは、過去の探索時の経験データ(オフライン経験データ)を活用する学習フローを取り入れることで探索の回数を削減します。実際、ロボットアーム実機を用いた実験により、先行研究と比べて少ない経験データ数にもかかわらず、より高い把持成功率を達成したことが報告されています。

以下で、論文の詳細を見ていきましょう。

論文の実験設定

実験では、KUKAのロボットアームと把持対象の物体が置かれているトレイを用意し、トレイ内の物体を把持する問題を考えます(図1左図)。ロボットアームの先端には、グリッパーと呼ばれる2本指が取り付けられており、この指を開いたり閉じたりすることで物を掴みます。ロボットアームの肩にはRGBカメラが取り付けられており、このRGBカメラによってロボットアームはトレイ内を観測できるようになっています。

把持を強化学習の問題として扱うために、実験ではRGBカメラから得られた画像をもとに状態を定義しています。効率的な学習のため、画像に加えて、グリッパーが開いているか閉じているかを示すバイナリ値とトレイからの高さの情報も状態に含めています。行動はロボットアームをどのように動かすかを示す制御コマンドで、グリッパーの移動方向と移動量、回転量、グリッパーを開くか閉じるか、そして把持動作を終了するか否かといった命令からなります。最後に、報酬は物体を把持出来たときに1、それ以外は-0.05と設定しています。ここで、-0.05は把持までの行動回数が多くなりすぎないようにするためのペナルティとなっています。

ロボットアームの学習時は、図1右図で示した多様な物体を用いて把持を行って得られた経験データを用います。一方、評価の際には、学習時とは異なる物体を用いることで、把持能力の汎化性能、すなわち未知の物体にも対応できる把持能力を獲得できているかを検証しています。
左図は実験に用いられたロボットアームとRGBカメラからの画像。右図は学習時の把持対象物体。
図1 (左図)実験に用いられたロボットアームとRGBカメラからの画像。(右図)学習時の把持対象物体。[1] Figure 2. より。

QT-Optで学習したモデルの性能

ここでは、QT-Optで学習したロボットアームの評価結果を見ていきます。

把持成功率は96%という値が達成されています。強化学習を用いないLevine et. al. [2] の手法では、把持成功率は78%であり、QT-Optを用いることで大きく性能が向上しています。また、先に触れたように評価では学習時とは異なる物体を用いているため、この96%という数字からは十分な汎化性能が得られていることも分かります。

把持能力の定性的な評価結果については、公開されている動画にまとめられています。この動画を見ると、ロボットアームがかなり柔軟な行動をできるようになっていることが分かります。この動画の前半では、物体同士が密着しており掴む箇所がない場合に、ロボットアームが物体の位置を一度ずらしてから把持を行う様子を見ることができます。また、動画後半(1:25 ~) では、把持対象のボールを途中で動かし、把持の邪魔をした時の様子が報告されています。ロボットアームは、邪魔をされても、もう一度把持を試みて無事にボールを掴むことに成功しています。把持という目標を設定することで、このような複雑な行動をも学習できてしまうというのは非常に興味深い点で、学習後のロボットアームの性能に感動し、上の動画を何度も再生してしまいました。

オフライン経験データを用いたQT-Optの学習

さて、ここからはQT-Optについての説明をまとめていきます。QT-Optは先行研究に対して、安定性・複雑なタスクへの対応力や並列処理の点で工夫を加えています。ですが、全てを説明するとかなり長くなってしまうので、メインのアイディアとなる「過去の探索時の経験データの利用」に焦点を絞ってまとめていきたいと思います。

QT-Optは、深層強化学習の体表的な手法であるDQNを拡張した手法となっています。QT-Optの説明に入る前に、まずはDQN[3]について説明しておきましょう。

DQNは、Q学習と呼ばれる手法をディープニューラルネットワークに一般化した手法です。DQNの大きな特徴の一つに、「経験リプレイ」という仕組みがあります。前に、強化学習では探索により経験データを集めて、その経験データから学習を行うと述べました。Q学習では、探索で集めた経験データを一度学習に用いると、すぐに捨ててしまいますが、DQNでは集めた経験データを一時的なバッファにためておき、学習時はそのバッファからランダムに選んだ経験データで学習を行います。この仕組みが経験リプレイで、多くの深層強化学習手法で経験リプレイやその改良版が用いられています。

さて、QT-Optではこの経験リプレイを、過去の学習時の経験データ(オフライン経験データ)にまで拡張しています。DQNでは、一時的に経験データをためておくだけで、バッファがいっぱいになったら過去の経験データは捨てていき、学習が終わった時にはバッファに残っている経験データを全て捨ててしまいます。一方、QT-Optでは、過去の学習時の経験データを捨てずにストレージにためておき、次の学習時の経験データとして用います。探索を新たに行うのは、学習の最終段階だけで、少量の経験データだけを収集します。

アイディアはとてもシンプルなのですが、探索が高コストなロボットでは、探索したデータを効率的に再利用できるこの仕組みは非常に重要な工夫となります。ここで気になるのが、この仕組みで(1)オフライン経験データを用いた学習が上手くいくのか、そして(2)オフライン経験データはどのように集めるのが良いか、という点です。(1)については、実際に96%という高い把持成功率を達成できていることから、上手く学習できているといえるでしょう。この把持成功率を達成したときの学習の流れはこの後でもう少し詳しく見ていきます。(2)については、続く節にて論文のAppendix C.1について触れようと思います。このAppendixでは過去の経験データの内訳が学習結果に与える影響が考察されています。

それでは、オフライン経験データを用いたQT-Optの学習の流れをまずは見ていきましょう。QT-Optの学習は、大きく2つのフェーズに分かれています。学習の初期には、あらかじめ収集した経験データを用いてオフライン強化学習を行います。96%の把持成功率を達成した最終的な学習では、人間がプログラムした動作から得られた経験データや把持成功率が50%を超えた学習モデルの経験データを用いており、把持試行としては58万回分の経験データを学習に利用しています。学習が一定の段階まで進むと次のフェーズに移り、学習中のエージェントによる探索も行います。ここで新たに集める経験データは、オフライン経験データと区別するためオンライン経験データと呼びます。このフェーズでは、オンライン経験データをオフライン経験データに加えながら学習をさらに進めていきます。オンライン経験データはオフライン経験データと比べて少ないため、学習に使用するオンライン経験データの割合を徐々に上げながら学習を行うことで過学習を防ぎます。最終的な学習では、このフェーズで2.8万回の把持試行を行っています。

さて、QT-Optによるロボットアームの学習ではトータルで60.8万回の把持試行を行っているわけですが、Levine et. al. [2]の手法では、78%の把持成功率を達成するのに90万回分の把持試行データを必要としています。Levine et. al. の手法と比べると、QT-Optは必要な把持試行回数を削減したうえで把持成功率を向上させることに成功しています。とはいえ、60.8万回というのは極端に少ない数字というわけではなく、経験データの収集には7台のロボットアームを用いて、4か月という時間がかかっています。経験データ数を削減できているとはいえ、まだまだ長大な時間がかかっている点は今後の課題のように感じます。

オフライン経験データの内訳と性能への影響

さて、オフライン経験データを用いることで、必要な探索回数を減らせるというのがQT-Optの重要なポイントですが、このオフライン経験データはどんなものでも良いと言うわけではなさそうです。論文のAppendix C.1 では、シミュレーション環境を用いた実験で、オフライン経験データの内訳の違いが学習結果に与える影響が考察されています。この実験では二つのエージェント\pi_{scripted}\pi_{eval}を用いて、経験データを収集し、それらでオフライン強化学習を行ったときの把持成功率を比較しています。\pi_{scripted}は人がプログラムしたエージェントで、xy方向に対してランダムにグリッパーを動かし、開いたままのグリッパーをトレイのある下側に移動させて、グリッパーを閉じ、元の高さまでグリッパーを戻すというエージェントです。\pi_{eval}はQT-Opt による学習で得られたエージェントを表します。ただし、\pi_{eval} はQT-Optで完全に学習したものではなく、この実験に用いられたエージェントはどちらも30%程度の把持成功率となっています。

実験結果は表1のようになっています。ここで、D_{scripted}D_{explore}はそれぞれ、\pi_{scripted}\pi_{eval}を用いて収集したオフライン経験データを表しており、使用する経験データ数に応じて4パターンの学習を行っています。

オフライン経験データの内訳と把持成功率をまとめた表。
表1 オフライン経験データの内訳と把持成功率。[2] Table 9 より。


表1の1段目と2段目が、D_{scripted}D_{explore} のそれぞれで、30 万個のオフライン経験データを利用した場合の把持成功率です。3段目と4段目が、2種類のオフライン経験データをミックスした場合の結果となっています。この結果を見ると、1つのエージェントで収集したオフライン経験データのみで学習した時(1段目と2段目)と比べ、2つのエージェントで収集したオフライン経験データで学習した場合の把持成功率が大きく向上していることが分かります。また、3段目と4段目を比較すると、オフライン経験データ数が多いほど把持成功率が高くなっています。

この実験結果からは、異なる性質を持つ複数のエージェントで収集したオフライン経験データを用いることが把持成功率の向上に役立つことが示唆されます。もう少し掘り下げて、論文では次のような考察がされています。\pi_{scripted} はある程度のランダム性は持つものの、グリッパーを閉じるまでは常にトレイのある下側にグリッパーを移動させるため、このエージェントによって集められる経験データは偏ったものになります。一方、\pi_{eval}はベストな性能ではないものの、トレイと逆方向にもグリッパーを移動でき、より多様な経験データを収集することが可能です。このAppendixでの実験結果と、前節で説明した学習フローによる結果を踏まえ、低い把持成功率のエージェントを用いた経験データからスタートしても、学習とデータ収集を繰り返していくことで、高い精度の把持成功率を得るのに十分な多様性を持つオフライン経験データセットが得られるだろうと述べられています。

実験

ここでは、QT-Optの論文、特に最後に紹介したAppendix C.1を踏まえて行った実験とその結果を紹介します。これまでにも述べたように、ロボット実機による探索は高コストであり、ロボットに強化学習を応用する際には、必要な経験データ数を抑える必要があります。その方法の一つが、QT-Optの論文で提案されたオフライン経験データを使用した学習法です。論文のAppendix C.1 からはオフライン経験データの収集手順の違いが、最終的な把持成功率に大きく影響することが分かります。これから紹介する実験では、シミュレーション環境を用いてオフライン経験データの収集手順の違いと把持成功率の関係を実際に確認してみました。

実験設計

今回の実験では、論文[4] で用いられているロボットアームのシミュレーション環境を用いました(Githubで公開されています[5])。細かい点ですが、実験を行いやすいようにコードのGitHubリポジトリのIssue [6] をもとに環境リセット時の挙動をカスタマイズしています。 このシミュレーション環境は、論文と同様に、トレイ内の物体を把持するタスクを扱います(図2)。QT-Optの論文と異なる部分として、状態はRGB画像のみ、行動はグリッパーの移動量の指示のみとなっています。物体に近づくと自動でグリッパーが閉じ、把持試行が終わるという少し簡略化された環境です。

実験に使用したシミュレータ環境。
図2 実験に使用したシミュレータ環境。[4] Fig. 1. より。
このシミュレーション環境には、学習用の把持対象の物体が900種類、評価用の把持対象の物体が100 種類用意されており、QT-Optの問題設定と同じように学習時と評価時で異なる物体が使用されます(図3)。

学習と評価用の把持対象物体。
図3 (a)学習用の把持対象物体、(b)評価用の把持対象物体。[4] Fig. 2. より。
使用するモデルのアーキテクチャとしては論文[1] と同一のものを利用しています。

実験では、論文のAppnedix C.1 と同じように、人手でプログラムしたランダムエージェント\pi_{scripted}とQT-Opt で学習したエージェント\pi_{eval}を用意し、それぞれで集めたオフライン経験データで学習を行った結果を比較しました。ここでランダムエージェントについては、論文[4] と同じ「random policy」を流用しています(実装は[7]で公開されています)。このエージェントは、xy方向にランダムにグリッパーを動かしながらグリッパーを下げていくという点でQT-Optの論文の\pi_{scripted}と似た設計となっています。ただし、このエージェントでは一定の確率でトレイとは逆方向の上側にもグリッパーを動かすように設計されています。

実験では、 ①「オフライン経験データ数によって把持成功率がどう変化するか」と、② 「オフライン経験データの内訳の違いによって把持成功率がどう変化するか」の2つの項目を検証するため、オフライン経験データセットとして次のA ~ Cの3種類を用意しました:
  • A: \pi_{scripted}による10,000回分の把持試行を行って集めた経験データセット
  • B: \pi_{scripted}による100,000回分の把持試行を行って集めた経験データセット
  • C: \pi_{scripted}による50,000回分の把持試行を行って集めた経験データセット + \pi_{eval}による30,000回分の把持試行を行って集めた経験データセット
データセットA vs データセットB が①に、データセットB vs データセットC が② に対応しています(時間の関係上、実験C は実験B と比べエピソード数が若干少なくなっています)。 \pi_{eval} は、データセットAで学習したモデル(実験の独立性を上げるため、次の結果で報告するモデルとは別のもの)を使っています。データ収集に用いたエージェントの把持成功率はそれぞれ、\pi_{eval}が39%、\pi_{scripted}は40%で、同程度の性能のものを用いています。

結果

以下の表では、オフライン経験データの内訳と学習後の把持成功率を示します。それぞれのデータセットで、オフライン学習を2回ずつ行い、学習後の評価用環境での把持成功率の平均値を求めています。

データセット\pi_{scripted}による把持試行回数\pi_{eval}による把持試行回数把持成功率
A10K039%
B100K062%
C50K30K70%
表2 オフライン経験データと学習後の把持成功率。


考察

データセットAとデータセットB で学習した結果を比較すると、オフライン経験データ数が多いほど把持成功率が高くなっています。検証項目①については、一つのエージェント\pi_{scripted}だけの結果ではありますが、経験データ数が多いほど良いというなんとなく予想できる結果となっています。

一方、データセットBとデータセットCで学習した結果を比較すると、実験Cの方がエピソード数は少ないにもかかわらず、データセットCで学習したエージェントの把持成功率が高くなっています。検証項目②については、2種類のエージェントによる経験データで学習した方が良いという論文Appendix C.1で期待されている通りの結果となりました。ただし、論文Appendix C.1の結果と比べ、データセットBとデータセットCの把持成功率の差はそれほど大きくありません。これは、環境の違いと\pi_{scripted}の設計の違いが影響していると思われます。特に、この実験で用いた\pi_{scripted}は、上方向の移動もランダムに発生するため、論文Appendix C.1 の実験と比べ、学習に有利となるようなオフライン経験データセットを\pi_{scripted}だけでも作れてしまったのではないかと予想しています。

まとめ

この記事では、深層強化学習手法QT-Optと関連して行った実験について解説しました。ロボット需要の高まりを考えると、認識と動作を一貫して扱え、複雑な行動方法について学習できる強化学習はロボットを多様な環境下に実投入していくための必須技術になっていくと思われます。一方、必要な経験データ量や経験データ収集のコストから、強化学習のロボット分野における成功例はあまり多くありません。今回紹介したQT-Optの論文[1] では、オンライン経験データに加えてオフライン経験データを有効活用することで、現実的な設定のもとで強化学習を成功させています。

実世界でのロボットによる探索コストを踏まえ、オンライン、オフライン経験データの両方を用いる強化学習手法はQT-Opt以降も発展しており、2021年のCoRLではAW-Opt[8]やOff2OnRL[9]など新しい手法も提案されています。こうした手法を取り入れていくことで、強化学習はよりロボットへ応用しやすい技術になっていくと期待しています。

紙面の都合上この記事では解説できませんでしたが、QT-Optでは確率的最適化アルゴリズムによる連続な行動空間のサポートや分散処理アーキテクチャなど、他にも興味深いアイディアが取り入れられています。興味がある方は直接論文を確認してみることをお勧めします。

ALBERTでは、様々な専門的バックグラウンドを持つリサーチャー・アナリストを募集しています。また、今回ブログで扱ったロボットや強化学習についても研究を行っており、お手伝いしていただけるアルバイトメンバーも募集しております。興味を持たれた方は採用ページから詳細をご確認ください。

参考文献

  1. D. Kalashnikov, A. Irpan, P. Pastor, J. Ibarz, A. Herzog, E. Jang, D. Quillen, E. Holly, M. Kalakrishnan, V. Vanhoucke, S. Levine. QT-Opt: Scalable Deep Reinforcement Learning for Vision-Based Robotic Manipulation. In Conference on Robot Learning, 2018.
  2. S. Levine, P. Pastor, A. Krizhevsky, and D. Quillen. Learning hand-eye coordination for robotic grasping with large-scale data collection. In International Symposium on Experimental Robotics, 2016.
  3. V. Mnih, K. Kavukcuoglu, D. Silver, A. Graves, I. Antonoglou, D. Wierstra, and M. Riedmiller. Playing atari with deep reinforcement learning. NeurIPS Deep Learning Workshop 2013, 2013.
  4. D. Quillen, E. Jang, O. Nachum, C. Finn, J. Ibarz, and S. Levine. Deep Reinforcement Learning for Vision-Based Robotic Grasping: A Simulated Comparative Evaluation of Off-Policy Methods. In 2018 IEEE International Conference on Robotics and Automation, pp. 6284-6291, 2018.
  5. https://github.com/google-research/google-research/tree/master/dql_grasping
  6. https://github.com/google-research/google-research/issues/14#issuecomment-475109307
  7. https://github.com/bulletphysics/bullet3/blob/master/examples/pybullet/gym/pybullet_envs/baselines/enjoy_kuka_diverse_object_grasping.py
  8. Y. Lu, K. Hausman, Y. Chebotar, M. Yan, E. Jang, A. Herzog, T. Xiao, A. Irpan, M. Khansari, D. Kalashinikov, and S. Levine. AW-Opt: Learning Robotic Skills with Imitation and Reinforcement at Scale. In Conference on Robot Learning, 2021
  9. S. Lee, Y. Seo, K. Lee, P. Abbeel, and J. Shin. Offline-to-Online Reinforcement Learning via Balanced Replay and Pessimistic Q-Ensemble, In Conference on Robot Learning, 2021

The post QT-Optの紹介とオフライン経験データに関する実験 first appeared on ALBERT Official Blog.

流れ星に全自動で願いを送る装置を作る

$
0
0
こんにちは。先進技術部でアルバイトをしている河田です。
流れ星に自動で願いを送る装置の試作品を作りました。
本記事では、作るまでの過程と作動の様子をお見せします。
なお、装置を動かすプログラムや装置の土台の3DモデルなどをGithubで公開しています。

はじめに

始まりは約3年前、ALBERT春インターンの打ち上げでした。
ちなみに、私はこのインターンに参加した後、今日に至るまでアルバイトとしてALBERTで様々な分野の研究をしています。
私は当時、大学の授業で画像から流れ星を識別する課題に取り組んでおり、打ち上げでその話をしていました。

すると、インターンを担当してくれた社員の山内さんから「自動で流れ星を検出して願いを送信してくれる装置があったら面白そうではないか?」という話が挙がりました。当時は面白いアイデアだなと思いはしましたが、まさか実現するとは思っていませんでした。

話が動いたのは半年前の雑談でした。私がなんとなく流れ星の話を出したところ、「せっかくだしやりましょう、この機会に!」ということになり、プロジェクトが始まったのでした。しかし、私は大学・アルバイトで画像識別をメインに研究しており、流れ星の方向を向き願いを送信する装置を作る方法など想像もつきませんでした。そこで、色々な方法を調査、模索しながらプロジェクトを進めることになりました。当初は完全にふざけた企画だと思っていたのですが、調べれば調べるほど様々な知識や技術が必要であることが分かってきました。

ここで、本プロジェクトの概要を述べます。

「流れ星が現れてから消えるまでに願い事を3回言うと願いが叶う」という言い伝えがありますが、本プロジェクトの目的はこれを全自動で行う装置を作ることです。

流れ星は一般的に、出現してから消えるまで約0.5秒[1]と言われています。仮に流れ星が見つけられたとしても、人間が0.5秒で瞬時に願い事を3回唱えるのはかなり無理があります。また、流れ星を見つけるためには街灯などの明かりのない場所に寝転んで夜空を見上げ、流れ星が流れるのをひたすら待たなければなりません。
先進技術部の山内さんが撮影した流れ星。
一般に販売されているカメラでも撮影することができる。
そこで、全自動で流れ星を見つけ、流れ星を追跡しながら高速で願いを送信できる装置の出番です。上記の背景から、できるだけ早く流れ星にレーザーを向け、正確に流れ星を追跡する仕組みが必要になります。

流れ星を自動で検出する既存手法として「流星電波観測」という方法があります[2]。これは、流れ星により電波が反射することを利用する方法です。正確には、流れ星が発光する際に周辺の大気が一時的に電離し、電子濃度が高くなることで電波が反射するのですが、いずれにしてもこの方法で流れ星を検出することができます。
また、この流星電波観測を使って実際に流れ星に願いを届けるプロジェクトが既に存在しています[3]。街のイルミネーションなどともコラボしており、非常にロマンチックで素敵な企画が多数行われているようです[4]。

ただ、流星電波観測では流星の正確な位置を掴むことができません。また、上記の「願いを届ける」というのも、流れ星を検知したタイミングで画面上に願いを表示するというような手法をとっており、直接流れ星に向けて願いを送っているわけではありません(なんだか理屈っぽいですね)。

そこで、本プロジェクトでは流星電波観測を使わずにカメラで流れ星を検出し、検知した流れ星に直接願いを送信することを考えます。 本プロジェクトでは、以下の方法で星に願いを送信します。
  1. 夜空をカメラで撮影し続けて流れ星を検出
  2. 検出した流れ星に向かってレーザーを照射
  3. 願い事を0/1の信号に変換し、それに合わせてレーザーを点滅させることで願い事を送信
流れ星はどんなデータ形式でも願いを受け取ってくれるはずなので、レーザーの点滅で願い事を表現します。また、どんなに小さな光でも願いはきっと届くはずなので、今回は一般的なレーザーポインターを使います。

レーザー光照射位置の動かし方

本装置にはレーザー光を流れ星に向ける仕組みが必要です。しかし、レーザーポインター本体を動かすとなると重量もあり、動かすのに時間がかかることが予想されます。
そこで、本プロジェクトでは「ガルバノミラー」[5]を使用します。ガルバノミラーとは簡単に言うとレーザー光を反射する鏡のことです。2組の鏡を適切に動かしてレーザー光を反射させることでレーザーポインター本体の位置を変えることなくレーザー照射位置を高速に動かすことができます。
ガルバノミラー(1枚の場合)。
レーザーポインター本体を動かすことなく、レーザー光照射位置を大きく動かすことができる。
今回は鏡をモーターで回転させることを考えます。モーターを制御するために、本プロジェクトでは「Arduino」というマイコンボードを使用します。Arduinoを使うことで、複数のモーターにそれぞれ命令を送って動かすことができます。
そこで、モーターの先端に鏡を取り付けてモーターを動かすことで、レーザーを反射する角度を調節することにします。
Arduinoを使って二つのモーターを制御している様子。
モーターの先端についている鏡を適切な位置にセットすることで、レーザー光を目的地に照射できる様になる。
ガルバノミラーをはじめとした色々な部品は、完成した精度の高いものが売られており購入することができるのですが、今回は基本的に1から作るという方針で進めました。

ARマーカーの追跡実験 〜ひとまず動かす〜

さて、いよいよ装置を作っていくのですが、いきなり屋外で流れ星を探してレーザーを照射するのは現実的ではありません。そこで、まずは下図の「ARマーカー」を流れ星と見立て、レーザー光がARマーカーを追跡する装置を作ることから始めます。ARマーカーはOpenCVにより画像から簡単に識別することができます。
ARマーカー。
これを紙に印刷して追跡する。
まずは鏡を1枚だけ使用して、レーザー光を横方向に動かすことを考えます。
カメラでARマーカーとレーザー光をそれぞれ検出し、二つの位置の差が縮まるようにモーターを動かしてレーザー光をARマーカーに近づけます。
なお、レーザー光は単純に撮影画像の明るい箇所を探すことで検出します。
カメラで撮影されたARマーカーとレーザー光。
二つの距離を小さくするようにレーザー光を動かす。
では、実験に移ります。まず、レーザー光を鏡で反射できるように、レーザーポインターと鏡を同じ高さにセットします。ARマーカーの位置に合わせて鏡が回転し、横方向にレーザー光の照射位置が動く仕組みです。
また、投影する壁が撮影できる位置にカメラをセットします。
各部品を設置した様子。なんだか”夏休みの自由研究感”が強い…。
ARマーカーを追跡した結果がこちらです。

第一段階としてはまずまずの結果になりました。ARマーカーの動きに合わせてレーザー光がARマーカーを追跡している様子が見て取れます。
一方で、ARマーカーを高速で動かすと、追跡するまでの遅延が顕著になります。流れ星は短時間しか見えないため、遅延はできるだけ減らしたいところです。
ARマーカーを高速で動かした場合。
レーザー光が追いつくまでに時間がかかっている。
さて、横方向に動かすことができたので、次は鏡を2枚使って2回反射させることで、縦方向にもレーザー光を動かすことに挑戦します。これにより、目標地点にぴったりとレーザーを照射できるようになるはずです。
各部品を設置。高さを合わせなければならないので箱やノートを使って調節
この日は晴れでレーザーが検出しにくかったため、部屋を暗くできる自宅の和室で実験。
レーザー光はまず上の鏡で1回反射し、その後に下の、2枚目の鏡で再度反射して壁に照射されます。下図の置き方をした場合、上の鏡がレーザー光の横方向の移動、下の鏡が縦方向の移動を担当することになります。
なお、1枚目の鏡で反射したレーザー光は2枚目の鏡でも反射する必要があります。そのため、二つの鏡が離れていると、上の鏡を動かせる角度が非常に小さくなってしまいます。そこで、広範囲にレーザー光を照射するためには1枚目と2枚目の鏡の距離をできるだけ近づける必要があります。
二つのモーターの位置関係とレーザー光の反射の様子。
二つの鏡はできるだけ近づけたいが、近づけすぎると鏡がぶつかる。
この実験でもARマーカーを追跡しますが、ARマーカーの中心にレーザー光を照射するとARマーカーの識別できなくなってしまいます。そこで、今後の実験ではARマーカーの左上を目標地点としてレーザー光を照射することにします。 実験の結果、レーザー光がARマーカーを正しく追跡していることが確認できました。
ARマーカーの左上を正しく追跡することができている。
しかし、これらの実験を通して様々な課題が浮かび上がってきました。
  • 1秒あたりの動作回数が少なく、遅延も大きい
    • この装置を動かすためには、「撮影→ARマーカーとレーザー光の検出→モーターの操作」と複数の段階を踏む必要があります。そのため、1秒あたりに命令を出せる回数が少ないという問題があります(1秒間に5回ほど)。また、各段階の処理に時間がかかるため、撮影してからモーターを動かすまでの遅延が大きいという問題もあります。
  • 各部品の位置を毎回調節しなければならない
    • 特にレーザーポインターや鏡の位置はレーザー光の照射位置に直接影響し、少しずれると目標地点に照射できなくなってしまいます。また、持ち運びにも大変不便です。将来的に屋外で使うことになった場合を考えると各部品を固定する必要があります。
  • レーザー光を検出して用いている
    • この実験ではARマーカーとレーザー光の位置を検出していましたが、最終的にはレーザーは夜空に向かって照射する予定であるため、レーザー光を観測することはできません。また、レーザー光は撮影画像の明るい場所を選んでいるだけなので、実験する日の条件によりカメラの絞りやゲインを都度調節する必要があります。
      さらに、撮影した画像における距離と実空間の距離は1:1で対応していません。例えば、カメラからの距離などによっても1ピクセルあたりの実空間での長さは変わります(カメラに近いほど大きく写る)。そのため、撮影画像における距離(ピクセル)の差から鏡を動かすと正確な目的地に到達するまでに時間がかかります。レーザー光が大きく動く場合を確認してみると、目標位置に向かう際に揺れる様な動きを見せながら徐々に動きが止まる様子が確認できます。これは、実空間での距離ではなく画像内の距離からモーターを動かしていることが原因です。
レーザー光がぐるぐる回りながら目標地点に近づいている。
これらの課題を解決するために改良を行いました。

ARマーカーの追跡実験 〜装置の改良〜

まず、1秒あたりの動作回数が少なく遅延も大きいという問題は、プログラムを「マルチプロセス化(非同期処理)」することで改善しました。具体的には、撮影と、ARマーカーなどの識別と、Arduinoに命令を送る処理をそれぞれ別プロセスで行うことで、各作業を待つ時間が短縮され高速に動く様になりました(1秒間に50〜60回ほど)。

また、3Dプリンターで装置の土台を作ることで、各部品を固定しました。 土台のモデリングを行う前に、紙にイメージを書いて大きさや形を決めていきました。
各土台のイメージ図
まず、モーターに取り付ける鏡を固定する土台を作りました。これまではセロテープでくっつけていただけだったのですが、3Dプリンターで土台を作ることで、モーターに対して正確に、垂直に固定することができました。土台の裏がわからボルトで固定しています。
鏡を固定する土台(鏡の背面の赤い部品)。
モーターの中心が鏡の反射面になるように、鏡の厚さも考慮して作成した。
次に、モーターやレーザーポインターの位置関係を固定する全体の土台です。これを作ることで部品の位置を調整する必要がなくなり、正確な位置に部品を置くことができるようになります。モーターやレーザーポインターは該当箇所に収めた後、ボルトで2カ所から押さえつけることでガタガタと細かく動くことがないようにしました。
装置全体の土台。
手前の細長い直方体の部分にレーザーポインターをセットしている。
ナットが入る穴を用意し、ボルトで2カ所から部品を壁に押し込むことで細かく動かないようにしている。
さらに、上のモーターにカメラを取り付けることで、全ての部品を固定できるようにしました。
カメラ、レーザーポインター、モーターの位置関係を固定。
モーターの回転数を決めるプログラムにも改良を加えました。これまでは撮影した画像に映ったARマーカーとレーザー光の位置の差をピクセル単位で計算して、その値を元にモーターを動かしていました。しかし、OpenCVを用いることで撮影されたARマーカーの実空間での距離(x, y, z)を取得できることを利用し、計算の仕方を改良しました。これはつまり、カメラからARマーカーまでの距離が○[cm]という風に計算できるということです。
実空間での距離が分かれば縦方向と横方向にそれぞれどの程度の角度でレーザーを照射すれば良いかが三角関数で計算できるので、そこからモーターのステップ数を簡単に計算することができます。
実空間での距離からモーターの回転量を決めることで、目標地点に到達するための必要ステップ数がぴったり計算することができるようになります。そのため、目標地点の周りをグルグルと回りながら近づく挙動をしなくなるはずです。

また、使用するデータはARマーカーの位置だけなので、レーザー光を検出する必要がなくなります。そのため、撮影画像にレーザー光が映らない夜空を想定した実験でもうまく動くことが期待できます。
加えて、わざわざ明るさの調整なども必要なくなりました。

しかし、カメラの位置とレーザーが反射する鏡の位置は厳密には異なります。また、取り付けたカメラの傾きなども影響してくる可能性があります。
そこで、カメラ座標系から装置座標系への変換行列をMLP(多層パーセプトロン)で表現して事前に学習し、より正確なレーザー照射を可能にしました。学習するパラメータは平行移動用の3個と回転用の3個、合計6個と非常に少ないので、学習もGPUを使わずに高速に行うことができます。

それでは、数々の改良を行った装置で、ARマーカーを追跡してみます。
先ほどの実験と同様、レーザー光は常にARマーカーの左上に照射するように設定しています。結果を見てみると、かなり高速でARマーカーを動かしているのにも関わらず、低遅延で正確に追跡できている様子が確認できます。
動作中のモーターの動き。
また、流れ星を高速で追跡できても、出現した瞬間に素早く流れ星にレーザー光を照射できなければ追える時間は短くなってしまいます。そこで、流れ星が出現した瞬間を再現するために、ARマーカーが出現した後どのくらい素早く目標地点に到達できるかを実験してみました。ARマーカーは一部を隠すと識別できなくなるため、指で上部を隠しています。
結果を見ると、かなり高速で目標地点までたどり着いていることが確認できます。また、改善前のように目標地点の周りをグルグル回りながら近づくのではなく、一回の命令で正確に目標地点に到達していることが確認できます。

流れ星を追う実験

さて、ここまではARマーカーを照射目的として追跡する実験をしてきましたが、実際に流れ星を追う場合はどのくらい正確に、素早くレーザーを照射できるのかが気になるポイントです。
そこで、Youtubeで流れ星の動画[6]を探してスクリーンに映し、その流れ星にレーザーを照射する実験を行いました。
実際に流れ星を検出するためには、雲や他の星の瞬きなどのノイズの影響があるため機械学習を用いる必要があると考えられます。しかし、今回はノイズの影響は考えずに前後のフレームの差分を取り、明るくなった部分を流れ星だと想定して実験を行います。流れ星の場合、画像から実空間でのx, y, z座標を求めることができませんが、スクリーンに映すことからz座標(カメラからスクリーンまでの距離)は確定しています。そこで、ARマーカーを使った事前学習の結果を用いて実空間でのx, y座標を計算します。

実験は下図の様に装置をセットして行いました。流れ星の光は弱く、これを明るさの差分で検出するため、完全に真っ暗にできる部屋で実験を行いました。レーザー光自身を検出しない様に、赤色の成分が強い光は検出しないように閾値を調整します。
スクリーンに映った流れ星をレーザーポインターで追跡する
流れ星の前に、画面にPCのカーソルを表示して、それをレーザー光で追跡する様子をお見せします。赤い光がレーザーポインターで照射しているレーザー光です。カーソルを低遅延で正確に追跡できていることが確認できます。
次に、速度と現れている時間が違う二つの流れ星を追跡した様子をお見せします。白い光が流れ星です。流れ星が現れた瞬間は光が弱く追跡することはできませんが、光が強くなるとレーザー光は瞬時に目標地点に移動し、その後は高精度に追跡できています。
この実験より、作成した装置を使うことで流れ星を高速、正確に追跡できることが分かりました。

今後の展望

本プロジェクトでは流れ星をレーザーで追跡する装置を作成しましたが、実は肝心の「願いを送る」部分が搭載されていません。願いを送る実験の準備は済ませているのですが、レーザーを点滅させる処理が増えると遅延が大きくなる可能性があるので、今回は割愛しました。
なお、レーザーを点滅させて信号を授受する事前実験では、”Hello world.”を表す96bitのデータの送信を、0.03秒で正しく行えていることを確認しています。今後、実際に使う段階まで本プロジェクトが進むのであれば、こちらの処理も必要になります。

また、今回の実験では考慮しませんでしたが、実際に装置を屋外で動かすことになった場合は雲や星の瞬きなどのノイズの影響も考えなければなりません。機械学習を用いるのであれば学習データが必要です。また、流れ星を検出するための適切なモデルも検討しなければなりません。

他にも、屋外かつ無人で使うのであれば、Jetson Nanoなどの低電力で動作する開発ボードを用いてPC無しで動かせるようにする必要があります。また、流れ星の移動方向の予測や照射位置の精度向上など、まだまだやれることは残されています。

失敗談、大変だったこと

ここでは、本プロジェクトを行う上での失敗談や大変だったことを記します。

電子工作の知識が皆無
最初につまずいたのは電子工作の部分でした。ジャンパ線の端子にはオスとメスの2種類があることが頭から抜けており、オスのジャンパ線のみを購入していたため、ひとまずセロテープでくっつけてなんとかしようとしました。全て自宅での作業になるため、何か部品が足りないとその都度商品を購入して自宅に送る申請を出す必要があり、関係者の皆さんには大変お手数をおかけしました。
セロテープでなんとかしようとした。
なんとかならなかった。
また、モーターを動かすためのドライバーには「はんだ付け」が必要でした。日頃から電子工作をされている方であれば、はんだごては家にあって普通に使えるものなのかもしれません。しかし、私の家にはなかったので会社ではんだごてを購入していただき、頑張ってはんだ付けしました。
意外な難関「はんだ付け」
はんだ付け前(左)とはんだ付け後(右)
・部品の破損
マイコンボードのArduinoやモータードライバーは過度な電圧を加えると、それが一瞬であっても破損してしまいます。今回作成した装置は命令系統の5V電圧とモーターを動かすための12V電圧が混在しているため、最新の注意を払っていたものの…破損してしまいました。2度。壊すたびに新しい部品を購入して送っていただかなければならないので、冷や汗を流しながら連絡することになったのでした。
なお、Arduinoは部品を交換して復活させることができました。

・Jetson Nanoを使ってみたかった
本研究ではPCにArduinoやカメラをつなげて実験をしていたのですが、屋外で長時間動かすことを想定した場合、PCを使うのは現実的ではありません。
そこで、当初はJetson Nanoという小型かつ低電力で作動する開発ボードを使うことを考えていました。
しかし、いざ使ってみようとすると必要なライブラリが入らなかったり、PCでは反応したカメラが反応しなかったり、様々な問題がありました。
わざわざJetson Nano専用のカメラ(e-CAM24_CUNX)を会社で買っていただいたりもしたのですが、OSを1から入れ直す必要があり、非常に時間がかかってしまったので結局今回は使いませんでした。

・3Dプリンター初心者
3Dプリンターの使い方も知らず、これも1から勉強することになりました。3Dプリントは非常に時間がかかるため、予め出社する社員の方に印刷をお願いして、後日取りに行くということもありました。ご協力ありがとうございました。
ボルトも3Dプリンターで作れるということを知り実際に作ってみたのですが、小さすぎたのか、密度の設定に問題があったのか、かなり脆いボルトができてしまいました。装置の鏡を固定する部分に刺したボルトは途中で折れて取れなくなってしまいました。
3Dプリンターで作成したボルト
折れたボルト
取り出せなくなったボルトの残骸が今も残っている

まとめと感想

本プロジェクトでは、全自動で流れ星を検出してレーザーで追跡し、願いを届ける装置の試作品を作成しました。実際に流れ星に願いを届けられるようになるまでには更なる改良が必要ですが、目的のものを作ることができました。

はじめは何もかも分からず全てが1からのスタートでしたが、やったことのない分野を勉強して新しい何かを学んだり作ったりするのは非常に楽しかったです。
今回のプロジェクトでは主にアルバイトの私が装置やプログラムの作成を行いましたが、社員の皆さんに大いに助けられてここまでやってくることができました。
部内にも専門家の方がいたわけではなかったのですが、相談や質問などに快く応じていただきました。また、私物の道具や本を貸していただくなど非常に協力的な体勢を取っていただき、スムーズに作業を進めることができました。
部外の皆さんにも大変助けられました。様々な商品を購入するたびに細かい手続きや自宅への送付の手間がありましたが、こちらも迅速に対応していただきました。ありがとうございました。

残念ながら私はこの流れ星のプロジェクトを最後にALBERTでのアルバイトを終了することになるのですが、3年間の長い期間で本当に色々勉強することができました。物体検出やセグメンテーション、クラス識別をはじめとした画像識別から、ロボットアームの操作やそのシミュレーション、ArduinoやJetson Nanoを用いた制御、3Dモデリングに至るまで、様々な知識・経験をALBERTでのアルバイトで得ました。週2回で細々と続けてきましたが、この経験が大学・大学院での研究にも大いに活きましたし、今後も活躍すると信じています。

もし、「この流れ星プロジェクトを引き継いでやってみたい!」という方がいらっしゃれば、是非こちらからアルバイトを申し込んでみてください。

また、ALBERTは日本屈指のデータサイエンスカンパニーとして、データサイエンティストの積極的な採用を行っています。興味を持っていただいた方は、採用ページもご覧ください。

参考

[1] “流れ星は – キッズ ギャラクシー”. 宇宙科学研究所.
https://www.isas.jaxa.jp/kids/faq/q_a/038.html

[2] “流星電波観測の歴史と仕組み”. 流星電波観測国際プロジェクト.
https://www.amro-net.jp/about-hro/hro1_j.html

[3] “Meteor Broadcaster”. Bascule.
https://meteorbroadcaster.com/

[4] “NIHONBASHI – 願いの森”. Bascule.
https://bascule.co.jp/work/negainomori/

[5] “ガルバノスキャナ AtoZ”. 株式会社 ティー・イー・エム.
https://www.tem-inc.co.jp/galvano/

[6] “ふたご座流星群2017“ (CC BYライセンス). nontan3458.
https://www.youtube.com/watch?v=rC7DMnIRErM

[7] “L6470デイジーチェーン接続のテスト“. 北の国から電子工作(仮).
http://spinelify.blog.fc2.com/blog-entry-81.html

いずれも2022/02/22に参照。

The post 流れ星に全自動で願いを送る装置を作る first appeared on ALBERT Official Blog.

「Heart Rate Modeling and Prediction Using Autoregressive Models and Deep Learning」の紹介

$
0
0
こんにちは、ストラテジックアライアンス部のStaffiniです。
2020年10月から、東京大学の大学院工学系研究科バイオエンジニアリング専攻で客員研究員として、計算疫学やヘルスケアのためのAIアプリケーション等を研究しています。

今回は、心拍数に対する異なる予測モデルを用いて分析を行い、『Sensors』 というジャーナルで2021年12月にパブリッシュされた論文「Heart Rate Modeling and Prediction Using Autoregressive Models and Deep Learning(自己回帰モデルとディープラーニングによる心拍数のモデリングと予測)」(https://www.mdpi.com/1424-8220/22/1/34 )を紹介します。

初めに

生理的機能の時系列は多くの要因に影響されて、急激に変化することもあるため、非線形性/非定常性だと思われています。その結果、心拍時系列は予測や取り扱いが困難とされることが多くあります。しかし、心拍変動の振る舞いは、心血管疾患や呼吸器疾患、気分障害などの基礎疾患を示すこともあります。このような特定の疾患の予防と制御のためには、心拍変動の正確なモデリングと信頼性の高い予測を用いて、良いパフォーマンスを発揮する適切なモデルを特定することが重要です。

長年にわたり、多くの研究が正確な心拍数予測のための様々なモデルを提案してきました。例えば、[1]は線形自己回帰(AR)モデルや線形自己回帰移動平均(ARMA)モデルの性能を非線形モデルやバイリニアモデルと比較し、予測には非線形手法を用いるべきと提案しました。ここでも、より最近の研究([2]-[3])ではフィードフォワードニューラルネットワークを検討し、[4]では心拍予測にAdam最適化アルゴリズムで学習したLSTMモデルを提案しています。これらの最近の研究は、高い粒度でデータを収集していましたが、単一のモデルを提案しており、単一の参加者と短い時間での検証のみでした。

このブログで紹介されている論文[5]では、粒度を低く(分単位のbeats per minute (BPM) 予測)しましたが、複数のモデルを比較し、12人の条件の異なる参加者で結果を検証しました。

論文の内容

この論文の参加者は東京にある5つの会社から募集されました。本研究では、対象者は介入群に属する者のみとしました。参加者には、心拍数をBPMで計測するウェアラブルデバイスFitbit Versa(Fitbit Inc.)を提供し、24時間装着してもらい、またライフスタイルや過去・現在の病歴に関するモバイルアプリを用いたアンケートにも回答してもらいました。母集団の分布をより正確に把握して、モデルのパフォーマンスをより良く評価するために、異なる特徴や心拍数行動を持つ12名の参加者を選びました。

現在までの疾患数、喫煙/飲酒習慣、運動習慣に関する情報は、研究開始時に実施したモバイルアプリベースの自己報告式アンケートによって抽出されました。一部、参加者が常時デバイスを装着していなかったため、記録されなかった心拍数の欠損値は、等間隔の時間グリッドを得るために、欠損データを線形補間しました。また、欠損値の補完を埋め込むコストを最小限にするため、欠損値が少ないことを12人の参加者を選択する基準としました。さらに、予測モデルの学習に用いたデータは、10日間に計測されたデータに限定しました(参加者1人あたり合計14,400回の観測)。興味がある方は、元の論文[5]に参加者の選び方とウェアラブルデバイスについての詳細な説明がありますのでご覧ください。

表1は、年齢、性別、病歴、喫煙/飲酒習慣、運動習慣を含む参加者の特徴をまとめたものです。
表1: 参加者の特徴。

収集したデータは、トレーニングとテストセットに80:20の割合で分割されました(すなわち、最初の8日間のデータをトレーニングに、最後の2日間のデータをテストに使用しました)。そして、分単位の心拍数予測に対して、複雑さを増す3つの異なるアーキテクチャ(AR、LSTM、ConvLSTM)のパフォーマンスを比較しました。

AR(自己回帰モデル)
次数{p}のARプロセスは、時刻{t}の時系列の値{X_t}を、その前の{p}個の実現値{X_{t-1}},{X_{t-2}},{...},{X_{t-p}}を用いて、以下の式に従ってモデル化します。

{X_t = \beta_0 + \sum_{i=1}^{p}\beta_i X_{t-i} + \varepsilon_t .}

ここで{\beta_0}はモデルの切片、{\beta_1, ..., \beta_p}は遅行値の係数、{\varepsilon_{t}\sim WN(0,\sigma^2_{\varepsilon})}であります。関心のある変数の実現値{X_t}は、{p}個の過去の実現値とノイズ項の線形結合を用いてモデル化されるので、ARプロセスは線形時系列のモデル化に特に有用です。

ARプロセスの適切な次数{p}を見つけるために、自己相関関数(ACF)や偏自己相関関数(PACF)の分析がよく使われます。我々の場合、検討したすべての参加者について、{p=3}が適切であることが確認されました。

LSTM(長・短期記憶)
LSTM [6]はRecurrent Neural Network(RNN)の一種で、情報の流れを制御できるメモリセルが存在するため、特に時系列予測などのシーケンス予測問題に適しているとされます。具体的には、各LSTMセルには、忘却ゲート(どの情報を破棄するかを決める)、入力ゲート(入力からどの値を用いて記憶状態を更新するかを決める)、出力ゲート(入力とメモリセルから何を出力するかを決める)の3つのゲートが存在します。ある時間ステップ{t}における方程式は以下の通りであります。

{F_t = \sigma(W_F x_t + U_F h_{t-1} + b_F),}
{I_t = \sigma(W_I x_t + U_I h_{t-1} + b_I),}
{\tilde{C_t} = tanh(W_C x_t + U_C h_{t-1} + b_C),}
{O_t =\sigma(W_O x_t + U_O h_{t-1} + b_O),}
{C_t = F_t \circ C_{t-1} + I_t \circ \tilde{C_t},}
{h_t = O_t \circ tanh(C_t).}

ここで、{F_t, I_t, O_t}はそれぞれ忘却ゲート、入力ゲート、出力ゲート、{\tilde{C_t}}はセル入力活性化ベクトル、{C_t}はセル状態、{h_t}は LSTM セルの出力ベクトル、{x_t}は LSTM セルへの入力ベクトルです。{W_., U_., b_.}はそれぞれ学習過程で調整する重み行列とバイアスベクトルのパラメータ、{\sigma}はシグモイド活性化関数、{\circ}は要素ワイズ積を表します。
データの複雑さと非線形性をよりよくモデル化するために、LSTMの層を互いに積み重ねることができます。この論文では、3層のLSTMアーキテクチャを使用しました。最初の隠れ層には 50 個のセルが含まれ、2 番目には 25 個、3 番目には 10 個のセルが含まれます。オーバーフィッティングを回避するため、各隠れ層の後にDropout[7]を適用しました(学習中に各セルをランダムにドロップする0.3の確率を適用しました)。また、Dropoutは最大ノルム正則化と組み合わせて、各隠れ層の重みとバイアスの両方のノルムが3以下になるように制約しました。この論文はシングルステップ予測に焦点を当てているので、出力層は単一の完全連結ニューロンから構成されています。最適化アルゴリズムとして、Adam [8]を使用して、学習率は0.001であり、これは実際にうまく機能することが示されています。隠れ層の活性化関数としては、LSTMで用いられる標準的な活性化関数であり、高速に収束できることが多い双曲線正接(tanh)を用いました。重みの初期化方式として、深層ネットワークによく効くGlorot uniform initializer[9]を各層に適用しました。モデルは2000エポック学習して、文献でしばしば示唆されるオーバーフィッティングを避けるための正則化の別の形態として早期停止を採用しました。

ConvLSTM(畳み込み長・短期記憶)
ConvLSTM [10]はLSTMアーキテクチャのバリエーションで、入力から状態、状態から状態への遷移に畳み込み演算を用いて、問題を時空間シーケンス予測問題として捉え直したものです。与えられた時間ステップ{t}におけるConvLSTMのセル方程式は以下の通りです。

{F_t = \sigma(W_F \ast x_t + U_F \ast h_{t-1} + V_F \circ C_{t-1} + b_F),}
{I_t = \sigma(W_I \ast x_t + U_I \ast h_{t-1} + V_I \circ C_{t-1} + b_I),}
{\tilde{C_t} = tanh(W_C \ast x_t + U_C \ast h_{t-1} + b_C),}
{O_t =\sigma(W_O \ast x_t + U_O \ast h_{t-1} + V_O \circ C_t + b_O),}
{C_t = F_t \circ C_{t-1} + I_t \circ \tilde{C_t},}
{h_t = O_t \circ tanh(C_t).}

ここで、すべての定義はLSTMの説明と同じです。演算子{\ast} は畳み込み演算を表して、{V_.}は学習に用いる別の重み行列です。
我々は2層のConvLSTMアーキテクチャを検討して、第1隠れ層は50セル、第2隠れ層は25セルとしました。出力層は1つの完全連結ニューロンで構成されました。LSTMのアーキテクチャと同じで、最適化アルゴリズムにAdam、隠れ層の活性化関数にtanh、重みの初期化スキームにGlorot uniform initializerを使用しました。ConvLSTMはLSTMと同じエポック数で学習して、早期停止を適用しました。

モデルの性能評価には、損失関数としては平均絶対誤差(MAE)と、大きな誤差をより大きく罰する二乗平均平方根誤差(RMSE)を選択しました。

{MAE =\frac{1}{n}\sum_{i=1}^{n}\left | \widehat{y_i} - y_i \right |,}
{RMSE =\sqrt{\frac{1}{n}\sum_{i=1}^{n}(\widehat{y_i} - y_i)^2.}}

ここで、{\widehat{y_i}}{y_i}はそれぞれ、{n}個の観測値に対する予測された心拍数値と真の心拍数値です。
ニューラルネットワークは、学習時に確率的な要素(重みの初期化など)を内在していることから、その結果は実行のたびに変化します。そのため、各ディープラーニングアルゴリズムは、各参加者について50回実行されました。
表2は、各モデルについて50回実行した平均値(および括弧内の標準偏差)を示しています。太字は、参加者ごとの最良の結果を示しています。
表2: 各モデルのMAEとRMSE。
表で報告された結果は、最もパフォーマンスの良いモデルがAR(3)モデルであることを示しています。結果はモデル間でほぼ同じでしたが、対応なし{t}検定により、12人の参加者全員について、MAEとRMSEに統計的に有意な差があることが確認されました(p < 0.01)。また、検出力分析により、対象者全員について高い統計的検出力(90%以上)が確認されました。
図1は、参加者1のテストセットにおいて、3つのモデルによって生成された分ごとのHR予測を示しています。
図1。参加者1名の予測結果。

考察

表2の結果から、3つのアーキテクチャ(AR(3)、LSTM、ConvLSTM)は同様の性能を示しましたが、線形ARモデルによる予測はLSTMとConvLSTMよりも統計的に有意に優れていることが分かりました。

得られた結果は、3つの考察を浮き彫りにしました。まず、{t}分の心拍数値は過去 3 分間の心拍数値と相関があって、この情報のみで正確に予測できます。他の参加者(無作為抽出)のデータを追加解析したところ、ACF/PACFプロットにおいて同じパターンが観察されました。第二に、分単位の心拍数予測は、計算負荷の高いツールを必要とせず、比較的容易にユーザーから心拍数情報を収集するウェアラブルデバイス(Fitbitなど)から抽出したデータを用いて行うことができます。第三に、より複雑なモデルは、わずかに悪い心拍数予測を生成しました。これは、1つ目の考察と一致して、心拍数の分単位の変化が合理的に線形過程とみなせることを示しています。

結論

この論文の目的は、分単位の心拍数予測に用いる3つの時系列予測モデルを比較して、心拍数行動のモデル化および予測の点で最も優れた性能を持つアーキテクチャを特定することであった。年齢、性別、ライフスタイルにかかわらず、個人の1分間の心拍数は、過去3分間の心拍数値に大きく依存して、1分ごとの心拍数変動は合理的に線形過程とみなせることが示唆されました。これらの知見は、ウェアラブルデバイスに比較的単純なモデルを実装することで、ユーザーに有用な情報を提供して、心拍数値の異常を監視して病気の発症リスクに対応できることを示唆しています。

最後に

この論文の拡張として、同じ3つのモデルを用いて、より長い期間(例えば、次の10分間)、多段階の予測を行って、モデルの相対的なパフォーマンスが変化するかどうかを観察することを検討しています。さらに、調査を進めることで、よりパフォーマンスの高いモデルが特定されられるかもしれません。

最後に、ALBERTでは一緒に切磋琢磨できるデータサイエンティストを募集しています!興味をお持ちいただいた方は、こちら(https://www.albert2005.co.jp/saiyo/?place=blog0711)までお問い合わせください。

参考文献

[1] Christini, D.J.; Bennett, F.H.; Lutchen, K.R.; Ahmed, H.M.; Hausdroff, J.M.; Oriol, N. “Application of linear and nonlinear time series modeling to heart rate dynamics analysis”. IEEE Trans. Biomed. Eng. 1995, 42, 411–415.

[2] Yuchi, M.; Jo, J. “Heart Rate Prediction Based on Physical Activity Using Feedforward Neural Network”. In Proceedings of the 2008 International Conference on Convergence and Hybrid Information Technology, Daejeon, Korea, 28–30 August 2008; pp. 344–350.

[3] Xiao, F.; Chen, Y.; Yuchi, M.; Ding, M.; Jo, J. “Heart Rate Prediction Model Based on Physical Activities Using Evolutionary Neural Network”. In Proceedings of the Fourth International Conference on Genetic and Evolutionary Computing, Washington, DC, USA, 13–15 December 2010; pp. 198–201.

[4] Luo, M.; Wu, K. “Heart rate prediction model based on neural network”. IOP Conf. Ser. Mater. Sci. Eng. 2020, 715, 012060.

[5] Staffini, A.; Svensson, T.; Chung, U.-I.; Svensson, A.K. “Heart Rate Modeling and Prediction Using Autoregressive Models and Deep Learning”. Sensors 2022, 22, 34.

[6] Hochreiter, S.; Schmidhuber, J. “Long short-time memory”. Neural Comput. 1997, 9, 1735–1780.

[7] Srivastava, N.; Hinton, G.; Krizhevsky, A.; Sutskever, I.; Salakhutdinov, R. “Dropout: A simple way to prevent neural networks from overfitting”. J. Mach. Learn. Res. 2014, 15, 1929–1958.

[8] Kingma, D.P.; Ba, J. “Adam: A Method for Stochastic Optimization”. arXiv 2014, arXiv:1412.6980. Available online: https://arxiv.org/abs/1412.6980

[9] Glorot, X.; Bengio, Y. “Understanding the difficulty of training deep feedforward neural networks”. J. Mach. Learn. Res. 2010, 9, 249–256.

[10] Shi, X.; Chen, Z.; Wang, H.; Yeung, D.Y. “Convolutional LSTM Network: A Machine Learning Approach for Precipitation Nowcasting”. arXiv 2015, arXiv:1506.04214. Available online: https://arxiv.org/abs/1506.04214

The post 「Heart Rate Modeling and Prediction Using Autoregressive Models and Deep Learning」の紹介 first appeared on ALBERT Official Blog.

書籍紹介『教えたくなるほどよくわかる 数学の基礎講座』

$
0
0
eyecatch

こんにちは。データコンサルティング部の飯田です。普段は自然言語処理に関する業務に携わっておりますが、このたび『教えたくなるほどよくわかる 数学の基礎講座』の監修を務めました。著者は、小さい子どもからオックスブリッジを目指す学生まで、幅広い生徒に数学を教えるクリス・ワーリング先生です。今回はこちらの書籍についてご紹介します。

book

教えたくなるほどよくわかる数学の基礎講座 | ニュートンプレス (newtonpress.co.jp)

日本ではあまり馴染みがないかもしれませんが、ワーリング先生は数学の面白さを紹介する本を何冊も書かれています。たとえばこちら。

From 0 to Infinity in 26 Centuries:
The Extraordinary Story of Maths by Chris Waring (goodreads.com)


「数学書なのだから、公式や定理が窮屈そうに並んでいるのだろうな」と思って手に取ってみると、最初の章が “Prehistoric Maths” – 「先史時代の数学」なのでびっくりします。そして続く章は “Stone Age” – 「石器時代」。考古学の参考書でしょうか?それとも歴史学?いいえ、数学の参考書です。数学と歴史、一見奇妙な組み合わせですが、ワーリング先生は型にはまった教え方にとらわれません。自由な発想で数学の楽しさを伝えてくれます。

たとえば、ALBERTの業務でもよく使う「相関」について取り上げてみたいと思います。その昔使った教科書では、ピアソンの相関係数の公式がページの中央に鎮座して、その脇にいくつかの例題と練習問題が添えられているだけでした。そこには公式の生まれた背景もなければ、先人たちが解こうと欲した問題もなく、不出来な学生だった私にとっては、どうにも味気ないものに思えました。授業で学んだときの印象は「いつかどこかで使うかもしれない、便利な道具」でしかなく、試験のあとには長らく思い出すこともありませんでした。

しかし『教えたくなるほどよくわかる 数学の基礎講座』では、ピアソンの相関係数が生まれるまでの経緯を交えて、とても印象的に教えてくれます。本書では、19世紀の統計学者であるフランシス・ゴルトンについて触れています。彼はチャールズ・ダーウィンのいとこであり、その著作『進化論』に影響を受けたのか、親のすぐれた特徴を子に引き継がせるメカニズムに興味を持っていたようです。ゴルトンが卓越していた点は、当時まだ「進化」も「遺伝」も整理されていなかったのにも関わらず、この現象を統計学的アプローチで解明しようと試みたことです。彼は「回帰」や「標準偏差」といった重要な概念を次々と考案していき、最後に相関係数のアイデアを教え子のカール・ピアソンに託しました。そしてピアソンは、師の期待に応えて相関係数の定式化に成功したのです……。以上、ピアソンの相関係数が生まれるまでの物語でした。もっとも現実の歴史はそこで終わらず、彼らの創始した優生学は多くの事件に関わり、やがてタブーにさえなるわけですが。

いかがでしょうか。私にはもう、相関を単なる分析のツールとしては見られません。関連したいくつもの歴史的な事実が連想されて、共分散と標準偏差とが映画のワンシーンのように思えます。もはや、試験がないからといって忘れることはないでしょう。


ワーリング先生はこうした世界史のような切り口だけではなく、色々な題材を用いて数学の面白さに気づかせてくれます。

相関についてもう一例挙げてみると、疑似相関を説明するのに https://tylervigen.com/ というWebサイトを紹介しています。こちらのサイトでは管理人のタイラー・ビゲン氏が疑似相関とみなすデータが公開されており、特にワーリング先生のお気に入りは「アメリカの原発のウラン貯蔵量」と「数学博士号の取得者」の疑似相関のようです。もちろん、原発にウランを運び込むことで博士号の取得者が増えるわけではありませんね。ちなみに私のお気に入りは「モッツアレラチーズの消費量」と「土木工学博士号の取得者」の疑似相関です。


本書を読み進めていくと「こうした教え方をしてくれる先生が、自分にもいたらよかったな」と思わずにはいられません。私が数学の面白さに気づくには多くの出会いが必要でしたし、それ以前の私にとって、数学とは大人になるための理不尽な通過儀礼に過ぎなかったのです。同じ思いをされて、数学にすっかり苦手意識を抱いてしまった方も少なくないのではありませんか。

そうした方にこそ、本書を読んでいただきたいと思います。数学は一見無機質で、拒絶感さえ与えるものですが、教科書には書かれていない物語を紐解いていくと、リアルな世界とのかかわりが具体的にイメージできるようになり、ぐっと距離が近づいてきます。

ちょっとしたエッセイを読むつもりで、この数学書を手に取ってみませんか。

最後にちょっと宣伝を。ALBERTは日本屈指のデータサイエンスカンパニーとして、データサイエンティストの積極的な採用を行っています。興味を持っていただいた方は、採用ページもご覧ください。

以上です。それでは、ごきげんよう。

The post 書籍紹介『教えたくなるほどよくわかる 数学の基礎講座』 first appeared on ALBERT Official Blog.

2022年4月、ALBERTに12名の新入社員が入社しました。

$
0
0
2022年4月に行われた入社式は、対面形式での実施となりました。
(撮影は感染予防対策を講じたうえで実施しました)

今年は12名の新入社員が入社しました。

入社初日は感染予防対策を万全にした新宿オフィスに新入社員を迎え、社長、執行役員から新入社員へのメッセージ、さらに同期同士のエンゲージメントを深めるためのコミュニケーションワークショップなどが行われました。

■松本社長からお祝いのメッセージ

『超えられないハードルはない』

松本社長が経営者になったときに意識するようになったという、仕事の心構えについて話がありました。

「社会人になると様々な困難が現れるが、自分の前に立ちはだかるハードルは必ず超えられると思うようになった。それは過去の自分が蒔いた種であるはずだと。今後、みなさんにとって学生時代にはあまり経験したことのないハードルが出てくると思うけれど、『大丈夫、超えられる』と信じて対応していってほしい。」

と激励のメッセージを贈り、新入社員の皆さんは真剣な眼差しで松本社長の話を聞いていました。
新入社員へお祝いのメッセージを贈る松本社長

■コミュニケーション研修

チームで工夫するトランプタワーづくり

入社2日目には、新卒社員同士のコミュニケーションを促進するためのワークショップをおこないました。まずはトランプタワー。Aチーム、Bチームに分かれ、54枚のトランプでどちらが高いタワーをつくれるか挑戦。5分の作戦タイムを使って皆でアイデアを出し合い、いよいよ作業スタート!作業が始まると各自の役割に集中しつつも、みなさんよく声が出ていました。
作業の分担が速やかで、セロテープを一定の長さに切って用意する人、貼り合わせの作業に専念する人。「この貼り方はいいみたい」「ここが歪んでいるとバランスがよくないかも」と静かに作業をすすめるなかでも、それぞれが意見を出しながら意識を合わせていく様子もみられました。チームそれぞれの戦略で進めています。

組み立ての担当者は、どちらのチームも専任1名での作業。土台の歪みなど、専任ならではの気づきもあったようです。トランプが崩れてしまうと、残り時間で再度組み立てなければと、焦る気持ちが手を急がせます。1ゲーム目のチャレンジ終了時間が来てしまい、ここで高さを計測。

1ゲーム目ではAチームのタワーが高く、勝利。Bチームは改善に向けて真剣に相談。どの方法が最もよいのか。図形と寸法の計算が、彼らの頭の中ですごい速さでおこなわれ、次の形態が決まったようです。
そして、2ゲーム目の作業スタート!
Aチームは、ぐらつきを補正するための新アイデアで、三角柱を重ねて高さを作っていく作戦。

Bチームは、競合(Aチーム)の1ゲーム目の立て方を参考に、間に1枚のトランプをはさみながら立てるというやり方に。積み上げながら計測してみたり、さらに高くできそうか、とチャレンジで載せてみたり。

どちらも先ほどよりもより楽しそうに作業が進みます。

最後の計測ではBチームが84㎝の高さとなり…ここで、人事から終了のホイッスル! 1-1の引き分けということになりました。
その後、作業の振り返り、チームワークの振り返りをおこないました。
自分たちの計画と改善したポイントはどこにあったか?
Aチーム:上流の作業と下流の作業とのコミュニケーションによって、よりトランプタワーの品質が高まるのでは、と感じた
Bチーム:一回目の立て方では負けてしまったため、二回目では改善のポイントを探り作戦を立てた。さらに効率よく建てるためのアイデアを実施することで、高くすることができた。
それぞれの気づきが得られたようです。今回のゲームは勝敗を決めるというよりも、仲間とのコミュニケーションによってそのプロセスや結果を共有していくことに意義を見出せるような楽しく濃いワークショップでした。  次は、さらにお互いの理解を深めてもらうための、コミュニケーション型ワークショップを実施しました。

■コミュニケーション研修

共通概念を作り上げるためのディスカッション

12名がAチームとBチーム、6名ずつ分かれ、各チームのリーダーを1名選出。 アメリカでおこなわれた意識調査をもとに、動物ランキングを主観で作成し、各自の回答(ランキング)を踏まえたうえで改めて「チームとしての回答(ランキング)を決める」というワークショップ。

各チーム6名ずつに分かれて議論を進めます。

1つのチームのリーダーは、公平性のある平等な決め方の相談など、チームの仲間に合意できるかやり方かどうかを確認しつつ、決定へのプロセスを提案していました。

また、他方のチームリーダーは、皆の意見を踏まえて丁寧に順位を決め、チーム全員合意の回答としてまとめるように進めていました。

どちらのチームもそれぞれのチームメンバーの意見を尊重していました。

このコミュニケーション研修の最後には、ワークショップの意図について解説がありました。 「チームで話し合い、意見を出し、案を修正することによってより標準的な回答に辿りつく。合意のためのプロセスが、ビジネスにおいて意味ある結果を導く。」という説明を受け、それぞれのチームが出した答えの解釈にも納得感があったようです。

◆さいごに

今年は新型コロナウィルスの影響も鑑みながらも、対面での入社式、オリエンテーション、コミュニケーション研修の開催となりました。新卒メンバーの同期同士の関係性づくりに焦点を当てたワークショップ実施。その甲斐もあり、現在はお互いにサポートし合いながら学んでいる様子です。
そして、研修期間中は先輩社員との交流企画も設けられています。彼らがこれからも安心してALBERTで働き、成長できるよう部門間連携をおこないながら、サポートを続けていきたいと思います。

約3か月間の研修を経たあと、新入社員はデータサイエンティストとして各部署に配属されます。ぜひ、今後の活躍にご期待ください!

The post 2022年4月、ALBERTに12名の新入社員が入社しました。 first appeared on ALBERT Official Blog.

マイナビ主催学生向けイベントのDXセミナーに登壇しました。

$
0
0
ALBERTは、マイナビと共同で、学生から社会人まで総DX人材化に向けて、社会で活躍できるDX人材の育成を支援するサービスを提供しています。

今回は、6月4日開催のオンラインと6月12日開催のリアルイベントにALBERTのメンバーが登壇し、学生にとってまだあまり馴染みの少ないDXについて、少しでも興味を持ってもらい、社会人になったときのスタートダッシュに役立てもらうべく、DXの基礎的な考え方や具体的な事例紹介などを行いました。


6月4日 仕事研究&インターンシップWEB EXPO JAPAN【全国】

オンライン開催だった6月4日のイベントでは、「触れてみよう、知ってみようDX」と題して、マイナビ人事部長の谷本様とDX講座の人気講師でもあるALBERTデータサイエンティストの巣山、ファシリテーターとしてマイナビ編集長の高橋様の3名が登壇しました。

この日開催されたイベントの最後のプログラムであり、学生の方は果たしてDXに興味を持っているのだろうか、参加者が他のプログラムに比べて少ないのではないか、と開催前には少し不安があったものの、休日の夜にも関わらず、延べ参加者数1,200名を超える方が参加してくれました。
これには登壇者の皆さんも驚いており、私たちが考えている以上にDXに対する興味関心や具体的なスキル習得の取り組みへのニーズが高まっていると実感しました。

また、参加した方の学部も様々で、工学系からデザイン系まで、文系理系関係なく幅広い学部の皆さんが集まっていました。

講演では、DXとは何かという説明やマイナビで昨年実施したDXインターンシップの紹介、インターンや就職活動時のアドバイス等、後半は参加者からの質問に回答しながら進行していきました。



(コメント一部抜粋)
●株式会社マイナビ 人事統括本部採用部 部長 谷本 健次 氏
「入社時にあった方がいい知識とは?」という質問をよく受けますが、私は、スキルも大事ですが発想力がより重要だと思っています。資格試験(例えばITパスポートなど)を持っているから採用するというよりは、それに取り組んだ前向きさや、なぜ、何のためにその資格を取得したのか、という点を重視して評価をしています。

また、私がよく自社で話しているのは、エンジニアを目指す方には「社会に出たときどう役に立てるかを考えるビジネス視点を持ってもらいたい。」、エンジニア以外の職種を目指す方には「身近なことでも、今やっていることをデジタル化、自動化させるとどうよくなるかと考えたりする視点や発想力を大事にしてほしい。」ということです。


●株式会社ALBERT データサイエンス教育部 セクションマネージャー 巣山 剛 氏
DXやデータサイエンスという分野は、必要とされるスキルが幅広く、必ずしもひとりで全ての能力を習得して実践していく、という必要はないと思います。一方で、社会人になったときにDXにつながる考え方が何も身にいていないとついていくのが大変なので、少なくとも「基礎的なITリテラシー(意識)」、「課題発見力(仮説思考)」、「ロジカルシンキング」「データを活用した検証(データを読む力)」の4つのスキルは身につけておくことをおすすめしています。


●ファシリテーター:株式会社マイナビ 就職情報事業本部 マイナビ編集長 高橋 誠人 氏
まずは、自分の成長のために挑戦することが大事です。学生なら、失敗してもたくさんチャレンジができます。
主体性をもって、とよく言われると思いますが、以前の「主体性」は仕事終わりに自分から「何か手伝えることはありますか?」と聞くこと等だったかもしれませんが、今は意味合いが変わってきたと感じています。自分で課題を見つけ、解決方法を考えながら多様な人材と協力して変えていけるかを考えられる人、が今求められている「主体性」のある人材、と言えるのではないでしょうか。



6月12日 仕事研究&インターンシップEXPO 東京会場

翌週は、東京ビッグサイトにて開催された大型のリアルイベントでの講演でした。

「AI・データ分析専門企業から学ぶ総DX人材化」をテーマに、株式会社ARISE analytics の執行役員でChief Workstyle Officerの佐々木様、ALBERT執行役員でデータサイエンス教育部長の平原、ファシリテーターとしてマイナビ編集長の高橋様の3名が登壇しパネルディスカッションを行いました。

久しぶりのリアル開催ということもあり、会場では多くの学生の皆さんの熱気が感じられました。プログラム参加の予約時点で満席。半数以上は文系の方で、また、女性の方が多く幅広く興味をもってお集まりいただきました。(EXPO最後のセミナーだったにもかかわらず、多くの方にご来場いただきました!)

会場では、ほとんどの学生の方がDXについて詳しくはないが興味は持っている、というやりとりがあり、3段階に分類されるデジタル化のうちDXと呼ばれるものはどのような位置づけにあるかの説明や政府によるDX推進の取り組みやその背景などが紹介されました。

また、デジタル人材とよく言われるなか、分析を行う人材だけでなく戦略やプロジェクトを推進する人、分析結果をシステム化して活用する人など様々な役割の人材が必要であることや、さらに「文系専攻の学生でも今から勉強してデジタル人材になれるのか?」という質問に対してはそれぞれ登壇者から、文系人材がDX人材としてどのような活躍の場があるのかをお話しました。

さらに、日常生活でも課題を見つけ、デジタルを活用してどう改善できそうかを考え、できることから実行していくサイクルが重要という話のなかでは、実際に参加した学生の方のアイデアを出してもらうなど、インタラクティブな交流もあり盛り上がりました。


(コメント一部抜粋)
●株式会社ARISE analytics 執行役員 Chief Workstyle Officer 佐々木 彰 氏
学生のうちにどんなスキルを学んでおけばいいかをよく聞かれますが、技術の進歩はとても早いため、今の最新技術を学生の方が学んでも、数年後に就職していざ使おうとしたらもう古くなっているかもしれないですよね。それよりも、新しいことにいかに早くキャッチアップしていくか、という訓練をするのがいいと考えています。

例えば、技術の仕組みを早く把握してクイックに実装してみることで、「これはこういう仕組みだと思うから、じゃあ自分はこうしてみよう」という動きができるようになります。これを繰り返して、考え続けることが大切です。
先ほどのアイデアだと、プロトタイプのアプリを作って学校に持ち込んでみるといいかもしれない。また、実際に出来上がらなかったとしても、それにチャレンジしたということが重要ですよね。


●株式会社ALBERT 執行役員 データサイエンス教育部長 平原 昭次 氏
学生のうちに、どんどん旅行に行くことをお勧めします。なぜなら、いろんな場所へ行って人と話したり、様々な体験を通して「気づく力」が身に着くからです。デジタル人材、特にDXの「X」トランスフォーメーションに向いているのは「いろんなことに対して疑問を持てる人、気がつく人」だと考えています。

東京にいると気づきにくいですが、地方に行くことで少子高齢化及び労働人口の減少によって、デジタル活用の必要性の視点でみると、多様な課題をより実感しやすいため、一足先に未来を見ているとも考えられます。旅行を楽しみながらも、デジタルを活用してもっとこうすれば、この問題を解決できるかも?社会がより良くなるのでは?という姿勢で考える機会をたくさん持ってもらいたい。


●ファシリテーター:株式会社マイナビ 就職情報事業本部 マイナビ編集長 高橋 誠人 氏
人生100年時代のなかで、これからさらにデジタル活用によるビジネスモデルの変革は待ったなしで進んでいきます。そのなかで、デジタルを活用できる、もしくは活用してビジネスを作れることは、皆さんのキャリアにおいて有利にしかなりません。学生のうちだけではなく、就職してからも学び続ける姿勢が今後ますます重要になります。自分で仮説を立て、課題解決の方法を考え実践していく、それを早いサイクルでどんどん繰り返していくことの重要性を本日学べたと思いますので、忘れないうちにぜひ実践していってください。



就活準備サイト『マイナビ2024』では、DXの定義や各業界におけるDX動向などの基礎知識を学習できる「DXがわかる!超基礎講座」​が提供されています。

マイナビの保有する人材採用・就職支援に関する知見やビッグデータと、ALBERTの持つ分析技術や専門人材育成ノウハウを活かして作られたプログラムで、専門用語などの丁寧な解説や豊富な事例を用いた説明により、どのようなスキルレベルの方でも理解しやすい内容となっています。



ALBERTでは、社内教育で培ったデータサイエンティスト育成サービスを提供し、企業の人材育成を支援しています。また、採用を積極募集していますので、少しでも気になるという方は、お気軽にお問い合わせください。

The post マイナビ主催学生向けイベントのDXセミナーに登壇しました。 first appeared on ALBERT Official Blog.

ALBERT × ARISE analytics、業界初の合同新卒研修を開催

$
0
0
研修は感染予防対策を講じたうえで実施いたしました。
今回は、ALBERT12名、ARISE analytics12名の総勢24名の新卒社員を対象に、2022年6月に行われた合同新卒研修の様子をお伝えします。

合同新卒研修については、5月26日に発表したプレスリリースでも紹介しています。
・ARISE analyticsとALBERT、業界初データサイエンス企業同士でデータ分析・AI活用等の専門領域における合同新卒社員研修を実施
~企業間交流を通じて、高度なデータサイエンス人材の早期育成を目指す~


一見すると、「ライバル企業同士なのになぜ?」と思われる方もいらっしゃるかもしれません。本研修は、国内外の多様化・高度化するデジタル化やデータ・AI活用の需要に対応し、専門人材の早期育成、データサイエンス業界全体のコミュニティや人材の質の向上を目指した活動の一環として企画されました。

ALBERTとARISE analytics

ALBERTとARISE analyticsは、時にはライバルでもあり、時には同じプロジェクトで協業する仲間でもあります。

ARISE analyticsは、国内最大規模のデータを保有するKDDIと、高度なコンサルティング力、アルゴリズム開発力を誇るアクセンチュア株式会社の強みを融合させたジョイントベンチャーとして2017年に設立されたアナリティクスカンパニーです。

2018年のKDDIとALBERTの資本業務提携を機に、ALBERTとARISE analyticsはビッグデータ分析のプロジェクト等における協業のほか、両社共同でKDDIの社内アナリティクス人材育成プログラムに対して、実践的な育成プログラムの提供等にも取り組んできました。

過去には、両社のデータサイエンティストが勉強会を開催するなど、データサイエンティスト同士の人材交流が行われています。
両社とも、国内トップクラスのデータサイエンティストが在籍しており、企業を超えたコミュニティを推進することで、技術やノウハウの共有やキャリアについての情報交換など、お互いにいい刺激となり、加速度的な成長が期待できます。

【勉強会についてのブログ記事】
「ARISE analytics社と合同で勉強会を開催しました」(2019年8月)
「ARISE analytics社と2回目の合同勉強会を開催いたしました。」(2021年10月)

合同新卒研修の概要

研修は、混合チームに分かれ、2日目からは各社のオフィスを活用しながら実施しました。


・実施期間:6日間(2022年6月1日~8日)
・参加者 :合計24名(ARISE analytics新卒:12名、ALBERT新卒:12名)
・カリキュラム:
 1日目:AI・分析プロジェクトの進め方
 2~5日目:異常検知講義・演習
 6日目:演習発表、総評、懇親会


ARISE analyticsオフィス
ALBERTオフィス

研修の様子

■1日目:AI・分析プロジェクトの進め方
初日は、まず両社の代表からご挨拶があった後、AI・分析プロジェクトの進め方について座学と簡単なワークショップを行いました。最初にAIプロジェクトのプロセス、プロジェクト計画の立て方、テーマの設定方法や陥りやすい失敗事例などを学びます。さらに機械学習について基礎的な考え方と手法について学んだ後、最初のワークショップです。

自分がある企業のDX部門の担当者になったと仮定し、各部門の持つ経営課題とデータを把握して、それぞれAIを活用した解決アイデアを出し合い、さらに「実現時のインパクト」と「実現可能性」で評価し、全社的に取り組むべき課題と解決策をチームごとに選んで発表しました。

その後、分析・運用の方針作成方法について再度座学を経て、先ほど各チームが選んだ解決策について、KPIや必要なデータ、分析手法、業務フローの作成などをディスカッションしてまとめていきます。

1日目の最終発表では、ユーザーごとのコンテンツ表示の最適化やコールセンターの業務効率化施策など各チームが選んだそれぞれの解決策について発表しあい、最後に講師からのフィードバックを受け終了しました。

ほとんどのメンバーはこの日が初めての顔合わせであったにもかかわらず、どのチームも、4人1組の2社混合メンバーで初日から活発に意見を出し合っていました。また、ワークショップの時間が1時間と短く、時間内にまとめられるのかと思って見ていましたが、全てのチームが決められた時間内に資料を完成させ、発表ではしっかりとそれぞれ検討した経緯や結果を説明することができていました。

■異常検知演習
2日目からは、プロジェクトを想定した、より高いレベルのアウトプットが求められる演習です。この演習では、実案件で想定されるようなデータを用いて一連の分析業務を体験し、各チームで分析、報告書作成、発表を行います。

初日のワークショップはそれぞれ1時間程度でしたが、今度は4日間かけて、実際に、前処理・基礎集計・分析⽅針作成・モデリング・精度評価といった⼀連の分析の⼯程を通して、学んだことへの理解を深めていきます。

今回の“クライアントからの依頼内容”は「機械の⾳から異常を検知できるモデルを作成したい」というものです。

詳細な要望には様々な優先順位や環境の制限などがあり、精度や速度評価等のバランスをみながら、そのなかで最適なモデルを(もちろん期間内に)構築しなくてはいけません。

実際のプロジェクトさながらに、使用できるデータセットが提供され、スケジュールと工数の管理も自分たちで考えながら行います。
4日間かけて、チームごとにAIモデルを構築し、データ分析・精度検証を進め、クライアントである担当者及び責任者向けに分析結果を報告書にまとめていきます。

■最終報告
最終日となる6日目は、6チームが順番に発表を行い、各社の先輩データサイエンティストからそれぞれのチームに対して分析結果や報告内容について評価とさらなる改善点などのフィードバックを受けました。

実際に分析した音声データを比較して音を聞かせながら説明を行うチームや、AIモデルを導入することで削減が期待できるコストを試算して示すチームなどもあり、中には、資料をほぼそのままクライアントに出しても大丈夫そう、という高評価を受けたチームもありました。

全体総評

最終報告の発表後、各社から参加していたデータサイエンティストのメンバーから6日間の研修を通しての総評が行われました。


(一部抜粋)
・報告するときは、(自身の)お母さんにもわかるような説明をすることを心掛けると良い。
・基本的な部分で差がでるので丁寧に仕事をすることが大切。
・今回の研修を通じて、他の人との考え方の違いや自分の強みを発見してもらいたい。
・今後も、(研修のように)100%で打席に立つ経験をたくさんしてもらいたい。
成長するためにはそれが重要。
・私たちの仕事は、いろんな特徴を持つ人と成果を出していく仕事。
今回の研修はとてもいい練習だったと思うので、今後の実務にもぜひ活かしてもらいたい。


最後に、各社の担当役員から「今後キャリアを築く上で支えあい刺激しあって一緒に成長していける関係性を作ってもらいたい」という今回の研修実施の意図と、「思ったような分析結果が出なくてもそれは無意味ではなく、選択肢を少なくしてより確実性を上げたという前進。私たちの仕事は常にファクトの積み重ねであることを常に忘れてはいけない」という激励の言葉をもらい、研修は終了しました。

研修を終えた各社新卒メンバーのコメント

>ALBERT S.Oさん(イニシャル)
「ARISE analyticsさんは我々に無い視点でアイデア出しや検討をされていて、さらにコミュニケーションが上手な方が多く感心していました。一緒に研修を受けられたのは、とても良い経験になりました!」

>ARISE analytics K.Oさん(イニシャル)
「技術力があり、データに真摯に向き合うALBERTさんの姿にとても刺激を受けました。また既に演習を経験されていたという事で、進め方などもリードして頂き、勉強になる事が多く大変充実した研修になりました!」


まとめ

今回取材する中で、講師メンバーからは、どのチームも発表のレベルが非常に高かったというコメントが多く聞かれました。
入社から合同研修までの研修内容は各社で違っていたため、参加者はお互いに意見を出し合いながらも、分析手法やモデル構築など技術面はALBERT、課題整理や合意形成などコミュニケーション面はARISE analyticsといったように各チームメンバーの強みを理解し、きちんと役割分担して効率的に進められていました。

各社の新卒メンバーは、合同研修後もそれぞれの企業で行われる研修を経て、実際のプロジェクトに参加していくこととなります。
これから、実務で苦労したりキャリアに悩んだりすることもたくさん経験すると思いますが、今回の研修を通じてできた関係性を活かし、企業を超えたコミュニティでお互いに切磋琢磨しながら成長していってもらいたいと思います。ぜひ新卒メンバーの活躍にご期待ください。


【採用情報】

ALBERTでは採用を積極募集しています!
少しでも気になるという方は、お気軽にお問い合わせください。

The post ALBERT × ARISE analytics、業界初の合同新卒研修を開催 first appeared on ALBERT Official Blog.


2022年度 人工知能学会全国大会(第36回)参加報告

$
0
0
ALBERTは今年2022年6月14日~17日に開催された人工知能学会全国大会(JSAI2022)に参加してきました。 4日間の様子について報告します。

ALBERTは2つの発表と企業展示に参加

毎年6月に開催される人工知能学会全国大会、2022年の今年は現地(京都国際会館)・オンラインのハイブリッド開催でおこなわれ、発表数は昨年の1.4倍、参加者は3,000名を超え、過去最も多くの人が参加した大会となりました。
ALBERTは本大会のゴールドスポンサーとして参加し、当社の先進技術部からインダストリアルセッション(企業プレゼン)と、インタラクティブセッション(ポスター発表)に参加しました。 企業展示ブースでは、たくさんの来場者が訪れてくれたことで、みなさんとの有益な情報交換をおこなうことができました。
企業展示ブース

■人工知能学会全国大会とは

今回で36回目となる人工知能学会全国大会。この大会では人工知能 (AI)に関連した研究発表が行われ、学生や大学教授、一般参加者や企業内の研究者まで、さまざまなバックボーンの方が参加しています。 2020年は急遽オンライン開催、2021年は完全オンラインでの開催でしたが、今年は京都会場への現地参加とオンライン参加によるハイブリッド開催となり、発表数は昨年比較の1.4倍増。参加者数は過去最高となりました(3029人)。 2023年は熊本城ホールにて開催の予定。 (学会についての詳細は公式HPをご確認ください。)
左:エントランス  右:会場案内図

ALBERTの発表

4日間の会期中に、ひと際賑わいをみせたのは、発表者と身近に話ができるインタラクティブセッション(ポスター発表)でした。ALBERT先進技術部の櫻井仁哉、山内隆太郎が研究内容「エネルギーベースモデルを用いた点群データからの表面再構成」の発表をおこない、準備したポスターの前には常時4~5名が訪れ、活発な質疑応答がおこなわれていました。 この研究内容は、先進技術部主導の研究型夏期インターン(2021年)で取り組んでいた内容を、櫻井仁哉が主著として発表しました。
左:ポスター発表時の様子  右:発表内容
インダストリアルセッション(企業プレゼン)では、先進技術部 部長の松林達史が当社の紹介に加え、先進技術部がおこなっている Computer Vision を中心とした研究(なかでも三次元認識)について話し、具体的な研究アプローチについて説明しました。こちらも現地会場・オンライン参加の多くの方に視聴いただくことができました。
先進技術部長 松林の発表の様子

ブースの様子

企業展示ブースでは、運営サポートとしてブランド戦略室 織田、関谷、人材戦略部 松田、石川が参加し、ALBERTの実績や技術領域の紹介、夏のインターン生募集のお知らせを行ないました。

最後に

人工知能学会全国大会は、1年に1度のイベントでしたが、日本国内の大学や企業が取り組んでいる研究の「いま」を知り、また、学生達の興味関心がどのような分野にあるのかを知ることのできる貴重な場であると感じました。 ALBERTが先端技術研究にも取り組んでいることを知ってもらうことができ、これまで以上に企業理解を深めていただく良い機会となりました。
ALBERTでは今後も技術発表などを積極的におこなってまいりますので、各種イベントでALBERTのブースを見掛けたら、ぜひお立ち寄りください。また、先進技術部の研究内容やリサーチャーを紹介しているサイトを2022年7月に新たにオープンしましたので、こちらもぜひご覧ください。

ALBERTは日本屈指のデータサイエンスカンパニーとして、データサイエンティストの積極的な採用を行っています。興味を持っていただいた方は、こちらの採用ページもご覧ください。

The post 2022年度 人工知能学会全国大会(第36回)参加報告 first appeared on ALBERT Official Blog.

中央大学の「AI・データサイエンス総合」で講義を実施

$
0
0
2022年6月18日に実施された中央大学の「AI・データサイエンス総合」にて、ALBERTのデータサイエンティストであり、データサイエンティスト育成支援事業で講師を担当している井田と巣山が、マイナビ編集長の高橋氏、理工学部の酒折准教授とともに、データ活用についての講義を行いました。

中央大学では、これからの時代が求める人材を育成すべく、文理を問わず全学部生を対象に「AI・データサイエンス全学プログラム」を開設し、新たな価値を見出す人材の育成を推進しています。

今回の講義においても、文理を超えて様々な学部から学生が参加してくれました。

左:ALBERT 井田、中央:ALBERT 巣山、右:マイナビ 高橋様

今回は、3回にわたって「DX(デジタルトランスフォーメーション)」をテーマにそれぞれの切り口から話をしてきた講義の最終日となります。

1回目、2回目では、企業が抱えるDX人材の課題やデータ活用人材の育成について説明や紹介が行われ、3回目となる今回は、「AI・データ活用による課題解決に関する議論」と題して、リアルとオンデマンドによるハイフレックス形式で開催されました。リアルでは7名、オンデマンドでは約50名が参加しました。

講義では座学に加え、ワークショップ(個人ワーク、グループワーク)を行いました。議論を通じて仮説思考を学生に実践してもらいながら、その重要性を感じてもらうことが目的です。



・仮説思考の方法とポイント(前回の振り返り)

まずは、前回までの振り返りも兼ねて仮説思考について説明がありました。

ビジネスにおいては、時間や情報が限られた中で判断をしていくことが求められます。また、仮説を立てて検証することを繰り返す中で、本質的な課題を見つけていく必要があります。データを使って仮説の妥当性を検証し、仮説が妥当ではないと判断した場合、別の仮説を立てて検証します。

さらに、「どのようなデータを使えばその仮説を検証できるのか」を考えていくことも重要です。仮説はあくまでも仮の結論であり、自分の主観も含まれるため、データによって根拠を示します。

今回のワークショップでは、仮説思考のフェーズのうち、
  • どのような仮説が立てられるか?
  • どのようなデータがあればこの仮説を検証できるか?

について、学生の皆さんに考えてもらいました。
ここで、講師から仮説の立て方について2つのステップを踏むと良いというアドバイスがありました。

ステップ1は仮説を立て方についてです。

自分がお客さんの立場だったら、上司だったらというように、自分以外の視点に立って考えてみる方法、「晴れの日によく売れるものは雨の日には売れにくいのでは」というように反対のことについて考えてみる方法、それからビジネスで用いられる3C分析、PEST分析のようなフレームワークを用いる方法などが紹介されました。

そしてステップ2は、立てた仮説の磨き方です。
ある程度たくさんの仮説が出てきたら、そこで終わらせず、「なぜ?」を繰り返し考えることで、仮説の内容をより深く本質的にしていくことができます。他の人とのディスカッションも重要で、自分だけでは気が付かなかった視点を得ることができたり、自分の仮説をより深めたりすることができます。


・ワークショップの様子

今回のワークショップは「とある大学において、人気度や倍率を高め、優秀な学生に集まってもらうためにはどうすればよいか」というテーマでした。

【どんな仮説が立てられるか】
まずは、どういった要因や課題が考えられるのか、個人ワークとグループワークを通じて仮説を出してもらいます。

仮説を考えるうえでは、正しいか正しくないかではなく、様々な観点から仮説を出すことが重要となるため、プラスに働くもの、マイナスに働くもの、それぞれ考えた仮説をたくさん出してもらいました。
参加した学生は、それぞれ少人数のグループに分かれ「大学の人気度に影響しそうな要因」について話し合います。

発表では、学部学科や学費、進学率など学業に関連するもの、SNSやホームページ、スポーツ支援等を活用した広報に関連するもの、通学環境や大学施設など設備に関するものが仮説として挙げられていました。また、インターンシップ・留学・資格取得などの課外活動へのフォローの手厚さや、学費補助などの経済支援等が大学の競争力や人気に影響するのではないか、という仮説も出ました。

SNSによる広報活動や学校の設備・環境に関する意見など、学生ならではの視点で考えられたものが多くあり、講師メンバーからは「その視点はなかった」という声もありました。

また、アドバイスとして「これから大学に入る高校生だけでなく、その学費を支払う保護者の視点も取り入れるとより考えの幅が広がり、現実的になる。また、大学生活4年が充実するだけでなく、そのあと社会でも活躍してもらいたいという思いに対して、就職支援やキャリア支援というキーワードもあるはず」というフィードバックには、学生たちも納得の表情でうなずいていました。

【どのようなデータがあればこの仮説を検証できるか】

次に、先ほど各グループで挙げた仮説に対して、どのようなデータがあればそれを検証できるかについて議論しました。こちらも、個人ワークののち、グループワークを通じて考えを深めていきます。先ほど同様にそれぞれの意見を出し合いながら、時折講師メンバーからのアドバイスをもらい、グループの意見をまとめていきます。

発表では、グループごとに先ほどそれぞれが挙げた課題に対して、どんなデータがあれば検証できそうか、どんなアイデアが出たかを紹介してもらいました。学部学科の数や種類、入学者数、大学院への進学率(他大学との比較)、入学希望者数と入学者数との比較や入学しなかった理由などが挙げられました。

また、設備についてはキャンパスごとの学生の満足度、志望度における施設の充実度の重要性(意識調査)、近隣大学との満足度比較などが挙げられ、やはり学生の皆さんにとって、立地や学びの環境はとても大きな要素なのだと感じました。

それに対してフィードバックでは、
「さっきよりも現実的になってきて、いい発表だった。今日の授業が終わっても実際にできる範囲でデータを調べてみて、自分たちの仮説がどうだったかを検証してみてもらいたい。」

「実際だと、立地条件があまり良くないキャンパスでもすごく人気があるところもあるので、そういったところはなぜ人気があるのかを調べてみるのも面白いかもしれない。」

「先ほどのアドバイスの視点をすぐに取り入れていた点が良かった。また、アンケートを取る方法もあるが、そうするとコストがかかることもあるため、まずは現状で確認できるデータから調べていくのもよい。」

等のアドバイスがありました。


・仮説思考の仕上げは各自がレポートで提出

当日の講義では、仮説の立案と検証データの考察までを行います。あとはレポートにて、仮説を検証した結果得られた情報をもとに、どうすれば学生の志望度を高め、入学者数を増やすことができるか方法を自分なりに考えて施策案を提出する、という流れになります。

最後に、3回の講義に参加いただいた皆さんに、マイナビとALBERTが共同開発した、
『DXがわかる!超基礎講座』を紹介させていただきました。

「DXがわかる!超基礎講座」は、就活準備サイト『マイナビ2024』にて提供されており、DXの概要や各業界におけるDX動向などの基礎知識を学習できます。(次回お申込みは10月3日予定)

マイナビの保有する人材採用・就職支援に関する知見やビッグデータと、ALBERTの持つ分析技術や専門人材育成ノウハウを活かして作られたプログラムで、専門用語の丁寧な解説や豊富な事例を用いた説明により、どのようなスキルレベルの方でも理解しやすい内容となっています。

DXの推進には様々なスキルが必要になりますが、DXにおける課題の発見や解決案の策定において仮説思考は非常に重要になります。

大学生には、これからどのような社会になっていくのか、またどのようなスキルが必要になってくるのかについて、今から知ってもらうきっかけにしていただきたいと思います。


・科目「AI・データサイエンス総合」について

(中央大学シラバス2022年度版から一部抜粋)
AI・データサイエンスを業務に適用している実務家を複数名お招きして、一連のテーマごとに授業を担当していただきます。
現代社会で解決が試みられている様々な課題に対して、AI・データサイエンスの手法が効果的に用いられた実践例と意義を、複数名の実務家から学びます。

リンク:AI・データサイエンス全学プログラムについて(中央大学受験生ナビ Connect Web)

リンク:AI・データサイエンス全学プログラム (全学連携教育機構)

また、中央大学の公式サイトでも本講義の様子について紹介されました。
科目「AI・データサイエンス総合」にて、株式会社ALBERT(アルベルト)井田 佳祐 様、巣山 剛 様、マイナビ編集長 高橋 誠人 様からの講義実施


【採用情報】
最後に、ALBERTではデータサイエンティストの採用を積極的に行っています
少しでも気になった方は、お気軽にお問い合わせください。

The post 中央大学の「AI・データサイエンス総合」で講義を実施 first appeared on ALBERT Official Blog.

2022年 新卒研修レポート

$
0
0
初めまして! 
2022年4月に新卒社員として入社しました、ストラテジックアライアンス部の渡邉、寺井です。

本記事では、2022年度の新卒研修の様子を紹介します。今年度の研修は3ヶ月に渡って行われ、技術研修・ビジネス研修・分析演習がありました。特にデータサイエンスに詳しくなかった私(寺井)でも、アナリストの卵として一通りのスキルを身につけられました。加えて、6月には今年度初の取り組みとして ARISE analytics様との合同研修が開催され、同世代のデータサイエンティストの輪を広げられました。以下では研修中に感じた内容を中心に詳しくお伝えします。

自己紹介

(渡邉)修士課程を修了後、4月にALBERTに新卒入社しました。学部時代は深層学習を用いた欠損値補完手法に関する研究に取り組み、大学院時代はベイズ統計学における特異学習理論と呼ばれる分野の理論解析をしていました。
(寺井)博士課程を修了後、4月にALBERTに新卒入社しました。大学院では非線形偏微分方程式の数学解析に取り組んでいました。

今年度、ALBERTには12名が新卒として入社しました。 
新卒メンバーの学生時代の専門分野は統計学や機械学習を始めとして、物理学・数学・生物学・経営学など様々です。入社前は、統計・機械学習の専門家や分析コンペの参加者ばかりなのかと思いドキドキしていましたが、他分野で熱心に研究に取り組んでいた人もいて意外に思いました。また、学業以外の面でもバラエティーがあり、趣味で大型バイクでツーリングする人や、テーマパークで長年アルバイトしていた人などがいます。その一方で職場での議論や雑談の場では、お互いの意見を尊重し合おうとする姿勢がいつも感じられて居心地が良いです。

オリエンテーションで行われた「価値観を知るカードゲーム」の様子。私にとって大切な価値観のカードを躊躇わず捨てている人がいて面白かったです。カードゲームの内容の詳細は2021年の記事をご覧ください。

研修内容 

研修は主に技術研修・ビジネス研修・分析演習に分かれています。 
  • オリエンテーション・社内各部署の業務内容説明 
  • 技術研修 
    • UNIX・クラウド・Docker基礎 
    • Python基礎 
    • GitHub基礎 
    • コーディング作法 
    • 機械学習の基礎 
    • 教師あり学習 
    • 教師なし学習 
    • 時系列分析 
    • RDB基礎 
    • Spark基礎 
    • 自然言語処理入門 
  • ビジネス研修 
    • ビジネスライティング研修 
    • プレゼンテーション入門 
    • 分析報告書の書き方 
    • ビジネスマナー研修 
  • 分析演習(5月) 
    • 離反者予測演習:音楽ストリーミングサービスにおける離反会員の予測 
    • クライアント対応演習:メーカーの検査工程におけるAIシステムの導入 
  • 分析演習(6月)
    • ARISE analytics様との合同研修 
      • AI分析プロジェクトの進め方 
      • 音声データの異常検知:水流音から異常音を検知  
    • 画像セグメンテーション:深層学習を用いた車載カメラの画像データの物体認識 
    • 信用リスク分析:クレジットカード利用者のデフォルトリスクの推定 
    • 顧客分析:商品購買データから商品軸・顧客軸による分析と施策提案 
大半の研修がオンラインで実施されましたが、クライアント対応演習および一部のビジネス研修は対面で実施されました。また、 ARISE analytics様との合同研修は両社オフィスで行われました。  今回の記事では、4月と5月の研修内容を渡邉が、6月の研修内容を寺井が振り返ります。

4月と5月の研修 

技術研修 

技術研修の形式は、 
  • 先輩社員が講師として教える講義形式 
  • 事前に講義を録画したものを視聴する VOD 形式 
の 2 パターンがありました。UNIXの基礎から始まり、データサイエンスの業務に携わるにあたり必要になる技術を学びました。講義形式の研修では、講義内容について受講者からの積極的な質問が飛び交っており、オンライン上でのコミュニケーションの取りづらさを全く感じない活発な議論が行われました。

ビジネス研修 

ビジネス研修では、ビジネスライティング・分析報告書の書き方・プレゼンテーション入門・ビジネスマナー研修を行いました。ここでは、今年度から新たに研修項目として追加されたプレゼンテーション入門についてご紹介します。 前半はVODを視聴してプレゼンテーションの概要を学習し、後半は「顧客の抱える課題を解決する分析手法を提案する」というテーマで個人演習を行いました。PowerPointで報告書スライド資料を作成し、プレゼンテーションを行いました。 私は学生時代でも研究発表等でプレゼンを行う経験はあったものの、プレゼンに対して他の方から「もっとこのように発表した方がいい」「資料はこう書くともっと分かりやすい」等のフィードバックをもらった経験は今までなかったため、この研修は自分にとってプレゼンテーションスキルを磨ける良い機会だと感じました。

離反者予測演習 

離反者予測演習は、新卒社員にとって初めての分析演習でした。この演習では、音楽ストリーミングサービスにおけるユーザーの契約履歴や会員情報、利用情報などのデータをもとに離反会員を予測し、離反会員を増やさないような施策を提案するという内容です。演習内容の詳細は2018 年2019 年2021年の記事に書かれておりますのでぜひご覧ください。 
この演習では、どのような会員が離反会員であるかがあらかじめ定義されておらず、データに基づき考える必要があるという、実務に近い演習形式でした。そのため、同じ課題に取り組んでいても、分析対象は受講者ごとに異なっており、自分とは違った視点からの考察を聞くことができました。

クライアント対応演習 

クライアント対応演習では2チームに分かれ、クライアントへのヒアリングから提案、分析、報告までの一連の分析プロジェクトの流れを体験するという内容でした。演習内容の詳細は2020年と2021年記事に、それぞれ分かりやすく書かれているので、ぜひご覧ください。 
私が所属したチームでは、チームメンバーのうち2人がデータの基礎集計を担当し、2人が機械学習モデルによる予測や評価を担当、残りの2人は資料作成を担当、というように、それぞれ役割分担することで限られた時間内に効率良く進めることを心がけました。クライアントとの折衝を体験できる貴重な研修であり、今までの技術研修やビジネス研修で得た知識を実際に活用できる機会になりました。

6月の研修 

6月は、大きなイベントとしてARISE analytics様(以下、ARISE様)との合同新卒研修がありました。その後に再び個人で分析演習に取り組みました。

ARISE様との合同研修 

6月からはARISE様の新卒社員の方々と合同研修を受けました。より詳細な研修内容は、以前のブログ記事「ALBERT × ARISE analytics、業界初の合同新卒研修を開催」をぜひご覧ください。ここでは、参加者目線で合同研修の様子をお伝えします。 初日はARISE様のオフィスにうかがいました。初の9時出勤、初の対外的なイベントということもあり、具体的な研修内容に入るまでは入社式と同じくらいの緊張感がありました。

研修初日、ARISE様のオフィス受付階に到着してソワソワしているALBERTメンバー
合同研修では、どの日程も各社混成チームでの演習が行われました。私の分析演習のチームは偶然にも(?)全員が数学系と情報系の研究室出身でした。バックグラウンドが比較的近かったこともあり、お互いの学生生活や研修内容の話から仲良くなることができました。ARISE様の新卒メンバーの方々はとてもフレンドリーで、昼食休憩や研修終わりに各々のオフィス近くのお弁当やラーメン店を紹介しあうこともありました。

ARISE様のオフィスにて
ALBERTのオフィスにて
ここでは研修のメインの一つである異常検知演習の様子を振り返ります。私のチームの場合、分析当初に計画していたモデリングでは施策に活用し得る精度が出ませんでした。そこで、別手法でのモデリング、施策の見直しの2つの方向でゴールを目指しました。両社の強みは、ALBERTは技術力、ARISE様はビジネス力という認識でしたが、私のチームのARISE様メンバーは分析技術においても造詣の深い方々でした。時間配分・分析作業・資料作成のどの工程でも、効率的な方法や新しい知識に出会う場面がありました。


合同研修は内容自体も充実していましたが、それ以上に同世代のデータサイエンティストの知り合いが増えたこと、新卒研修の段階で他社様のメンバーとチームを組んで一連の分析作業に取り組めたことが本当に贅沢な経験でした。研修準備や感染対策に尽力してくださった運営の方々ありがとうございました。初回参加者の感想として、来年以降もぜひ続いてほしいと思っています。

懇親会前夜にスマートカジュアルってなんだろうと同期と相談しておいて良かったです。
(研修は感染予防対策を講じたうえで実施いたしました。)

個人での分析演習 

合同研修後は、車載画像のセグメンテーション・信用リスク評価のモデリング・ECサイトの購買ログ分析の3つの分析演習(詳細は昨年以前の記事をぜひご覧ください)に取り組みました。しばらくグループワークが続いていましたが再びの個人演習です。  個人演習の良い点であり大変な点でもありますが、各々の苦手作業に向き合う時間があります。これまでの演習を通して、私の場合は、特に資料のまとめ方に課題があることに気づき、改善が必要だと感じていました。具体的には、研究発表では数式表現に長けた資料作成ツールや黒板を使っていたため、アナリストとして求められている資料作成のスキルや経験が足りていないと感じました。また、一枚のスライドに収める情報密度も大学院時代の感覚とは乖離があり、配属前に少しでも慣れておきたいという気持ちがありました。そこで、この演習期間では分析作業に時間を費やしたい気持ちを抑えつつ、資料作成の時間を多めに割きました。最初の演習に比べれば幾らか改善できた気がしていますが、今後も精進していこうと思います。

余談ですが、研修が終わりに差し掛かる6月中旬になって初めて同期会を開催しました。第一回はシュラスコを食べに行きました。

ALBERTでは社員同士の懇親会に補助が出ます
他の同期の一言コーナー 
  • 同期や講師(先輩社員)の方と話す機会が多く、想像よりずっと楽しい研修だった。 
  • 研修を通してさらに学びたくなった内容もあるので、業務の合間や自己研鑽の時間を使って理解を深めたい。 
  • 分析演習中にこっそり残業した場合は減点する、という注意があり時間管理の厳格さに驚いた。 
  • 日報やslackにて、同期のリアクションやつぶやきが見られて面白かった。 
  • 終礼や週に1回オンラインのランチ会など、先輩アナリストと交流の場が好きだった。

最後に 

6月末に研修が終わり、今はアナリストとして分析案件に携わっています。業界・案件に応じて知らなかった背景知識・考え方を垣間見ることができて面白いです。また、手の動かし方が全く分からず途方に暮れてしまうことは今のところないので、これは研修のおかげだろうと感じています。これからも1つ1つできることを増やしていきたいです。  最後まで読んでいただきありがとうございました。 


ALBERTでは積極的に新卒採用を行っています。 
ALBERTに興味のある方、データサイエンティストに興味のある方は気兼ねなくお問い合わせください!

The post 2022年 新卒研修レポート first appeared on ALBERT Official Blog.

2022年夏季データ分析実務インターンを実施しました。

$
0
0

2022年8月15日から26日にかけてALBERTの夏季データ分析実務インターンを実施しました。
今年の夏季インターンは依然コロナ禍ということもあり、去年に引き続きオンライン形式で行われました。 30人の参加者が3人1組の10グループに分かれ、下記のスケジュールで進められました。

今回は、その様子をレポート形式でご報告します。
—————————————-

・1日目:講義、演習内容説明、環境構築手順説明
・2日目:グループワーク開始/エンジニアリング勉強会への参加
・3日目以降:講師とのグループ面談(進捗報告や質問など)
・7日目:アナリスト勉強会への参加
・8、9日目:個人面談(振り返り及びフィードバック)
・10日目(最終日):グループ発表/質疑応答タイム

 —————————————-
はじめにオリエンテーションがあり、その後は今回の課題である異常検知についての講義やPythonの環境構築についての説明などが行われました。
2日目以降はグループ作業に取り掛かりながら、社員が行っている勉強会への参加や、oViceというバーチャルオフィスツールを使用し、社員と交流を深めました。


       初日の異常検知についての講義で使用された資料から抜粋。

        初日の異常検知についての講義で使用された資料から抜粋。

Pythonの環境構築についての講義で使用された資料から抜粋。

グループワークでは、どのチームもSlack(コミュニケーションツール)を用いてコミュニケーションをとり、お互いの知識を共有しながら、協力して課題に取り組んでいました。

   グループ面談で講師からのフィードバックを真剣に聞く様子。※右下がインターン講師

   グループ面談で、モデルの解釈性に関する可視化結果について講師に相談する様子。  

最終日はグループ発表が行われました。各グループ発表時間20分と質疑応答10分で行いました。
発表内容は主に分析目的に対する取り組みの概要や分析結果の提示とそれを踏まえた提案など、どのチームも分析の概要・意図・結果等が伝わるように心掛けていました。

                  最終日:グループ発表の様子。
今年のインターンも、さまざまな出身分野の学生にご参加頂きました。参加された学生にとってデータ分析の実践的な経験を積む良い機会となり、進路を考えるうえで貴重な体験となったようです。

ALBERTでは2022年10月より2024年卒向けの採用を開始いたします。
採用ページもぜひご覧になってください。

採用サイト  新卒採用サイト

The post 2022年夏季データ分析実務インターンを実施しました。 first appeared on ALBERT Official Blog.

2023年度新卒社員内定式を実施しました。

$
0
0

2022年10月3日、東京本社で2023年度新卒社員内定式を行いました。

昨年はコロナウィルスの影響によりオンラインで行われたため、今年は感染防止対策をしっかり行った上で2年ぶりの東京本社での開催となりました。 初めて同期と顔を合わせるということもあってか内定者の皆さんは少し緊張した様子。一同、真剣な面持ちのなか、内定式が始まりました。


■内定式


社長及び経営陣からの祝辞

代表取締役社長の松本、執行役員ストラテジックアライアンス部部長の安達、データコンサルティング部の副部長布施より、それぞれ祝辞が送られました。

お祝いの言葉に加え、ALBERTが目指す方向性、今後の展望、様々なことに挑戦をする大切さや学生のうちにやっておいた方がいいことについてのアドバイスや応援メッセージなどが話されました。

内定者自己紹介

その後、内定者の皆さんによるこれまでの研究内容や経歴、趣味などの自己紹介が行われました。内容はもちろんのこと、発表スタイルにも個性があり、それぞれ印象に残る自己紹介でした。

 


– 会社見学

採用担当者より東京本社のオフィス案内が行われました。

選考がオンラインで行われていたこともあり、オフィスに来ることが初めての内定者も多くいたので、皆さん興味津々でオフィスの説明を聞いておりました。

 

交流会

昼食を食べ、午後は内定者同士による交流会が行われました。先輩社員も交えたカードゲーム「Ito(イト) 」を使って親睦を深めました。

それぞれの価値観のズレを楽しむゲームなので相手のことを知るのにはぴったりです。内定者の皆さんの緊張もほぐれて、楽しんでいる様子が伺えました。

– カードゲーム


– ALBERTクイズ

毎年恒例になっているALBERTクイズ。
ウェブサイトなどには載っていない内容を集めたもので、かなり難易度の高い問題もあります。楽しみながらALBERTの新たな一面を知ってもらうきっかけになったのではと思います。

今年は10問のクイズを用意し9問を見事正解した最高得点者の方にはささやかなプレゼントが贈られました。


■まとめ

今年の内定式は2年ぶりのオフラインでの開催で、対面でのコミュニケーションがとれて内定者の皆さんからも好評でした。同期になる方々や先輩社員と直接会うことで、より入社の実感が湧いたのではないでしょうか。
来年4月から一緒に仕事ができることを楽しみにしています!

ALBERTでは、2024新卒の採用募集を行っております。
ご興味のある方はぜひ下記よりご応募ください!

▼【2024年卒】新卒採用(第1クール)
https://hrmos.co/pages/albert2005/jobs/000000111
※応募期限:2022年10月28日(金)15:00迄

≪参考情報≫

・24新卒採用サイト
https://www.albert2005.co.jp/new_grad/

・19卒・20卒・21卒社員の「データサイエンティスト座談会」
https://www.albert2005.co.jp/saiyo/member/crosstalk/4-1

・多様な業界でのプロジェクト実績例
https://www.albert2005.co.jp/saiyo/workstyle/case

・新卒採用パンフレット
https://www.albert2005.co.jp/new_grad/doc/2024_saiyo_pamphlet.pdf

・ALBERTオフィスツアー


▼以下でも情報発信中!

採用Twitter:https://twitter.com/ALBERT_Recruit
公式facebook:https://www.facebook.com/ALBERTInc/

The post 2023年度新卒社員内定式を実施しました。 first appeared on ALBERT Official Blog.

オンライン全社イベント『ALBERT DAY 2022』を開催しました。

$
0
0
11月25日、ALBERTでは昨年に引き続きオンライン全社イベント「ALBERT DAY 2022」を開催しました。
今年は9月29日に発表があったTOBに伴い、開催については紆余曲折ありましたが、運営メンバーが試行錯誤のなか、「ALBERTのこれまでの歩みを振り返り、これからの未来に向けて、みんなで一緒に歩いていけるようなイベント」をというコンセプトで開催されました。

当日は250名を超えるメンバーが参加し、Slackを活用した実況チャネルも総コメント数が1731件あり、大いに盛り上がりました。


今回は、そんな「ALBERT DAY 2022」の様子をご紹介します。


こだわりが詰まったオープニングムービー

オープニングムービーは、当時の振り返りを含め、企画検討までの運営メンバーが試行錯誤した様子などを取り入れた内容となりました。

当時の振り返りについては、ALBERT創立時にオフィスとして構えていた岩波ビル(代々木)から始まり、野村ビル(西新宿)、新宿フロントタワー(現地)を巡り、それぞれの地での懐かしい場面を彷彿させる構成となっており、こだわりと遊び心の詰まったオープニングムービーとなりました。


第1部企画「これまでのALBERT~17年の軌跡~」

まずは「これまでのALBERT~17年の軌跡~」と題して、ALBERTの17年間の歩みを振り返りました。

ALBERTの沿革を動画で紹介し、さらに当時をよく知る社歴の長い社員をゲストに呼び、座談会を行いました。ゲストからは当時の出来事や印象に残っている先輩や上司からの名言などの話を伺い、ALBERTのルーツについて振り返りました。

参加後のアンケートのフリーコメントでは、

「動画の編集が凝っていると思いました。内容もわかりやすく、新卒の私としては軌跡を動画形式で振り返ることができたのでよかったです。」

「映像と社員の方のお話で、設立の頃の雰囲気が感じられて良かったと思います。」

等、ALBERTの創立からの出来事や今の事業に至るまでの流れを理解できたというお声を多く頂くことができました。

第1部企画「プロジェクト紹介」

ALBERTが手掛ける多くのプロジェクトのうち、全社員投票により「話を聞いてみたい!」という声が多かった3つのプロジェクトについて、プロジェクト概要のほか、チームメンバーへのインタビューや打ち合せ風景などを撮影し紹介しました。

各チームの個性や雰囲気がよく出ており、メンバー同士の関係性やそれぞれの人柄なども知ることができました。

■第1部企画「ALBERT Award 2022」

昨年も好評だったALBERT Award。今年は、行動指針に基づいた6つの賞に対して、最も体現していたと思うメンバーに事前に全社で投票を行い、当日はその発表と受賞者による座談会を行いました。


受賞者座談会では、Slack実況チャンネルを活用した質疑応答なども行い、配信会場とオンラインでの双方向コミュニケーションができ、大いに盛り上がりました。

■ALBERT DAY Slack LIVEチャネル内のコメント数ランキング発表!

ALBERT DAY ではコンテンツ以外にも様々な演出や企画を行っています。その中でも今回初めて実施して大変盛り上がったのが、当日のコメント数の投稿数上位をランキングで発表するという企画です。

この企画は開催1週間前のMTGで運営メンバーの若手が発案したものでした。通常業務もあり忙しい中、すぐSlackのコメント数の集計用スクリプトを作成して、試験テストまで実施して完成させてくれました。こんなスピード感でアイディアをすぐ実行できる技術力と行動力は「ALBERTならでは」で本当に素晴らしいと思いました。

当日はそのスクリプトを用いてコメント数の集計を本番の裏側で実施し、結果発表は素晴らしい盛り上がりとなりました。

後日、コメント数上位5名には、賞品としてALBERTDAY運営メンバーオリジナルTシャツを贈呈しました!

■第2部企画 「出張 アルベルト越境ラジオ!」

2部では、先進技術部のYさんが社内コミュニケーションの一貫としてSlackで不定期に開催している「albert-radio」の拡大版としてoVice(※)を用いて「出張 アルベルト越境ラジオ」を実施しました。

こちらも技術者の貴重な話から日常のフランクな話まで聞けて楽しかった!というお声も多く好評でした。

■食事、ノベルティ&ギフト

今年も昨年同様、参加者には宅配で届く食事と、ノベルティグッズを準備しました。さらに今年は、TOBが発表されたアクセンチュアから全従業員向けにギフトを準備いただいたので、一緒に同封してメンバーの元へ届けられました。
ノベルティグッズはロゴ入りのPCケース、ギフトとしてメモ帳、書籍(2冊)がそれぞれお贈られました。
運営事務局メンバーが、心を込めて社内会議室で全員分のノベルティグッズ袋詰め(300個分)をしました。

■社内アンケートより

今年は、昨年の通信環境の反省点を活かし、Zoomウェビナーを活用してイベントを行いましたが、Zoomの機能制限や、画面設定、カメラ設定、音声設定と様々なところで課題が残るものの、イベント中は大きな配信トラブルもなく、進行もスムーズに終えることができました。

昨年に引き続き、2回目のオンラインイベントとなりましたが、実施に関しては「去年よりもアップグレードされていて大変快適でした。」とのコメントも頂けるなど高評価で終えることができました。

(以下、コメントの一部をご紹介します)
  • 誰かに認められ表彰されることは誇らしいと思います。今後のモチベーションにもつながりました。

  • オープニング、エンディングで開催コンセプトを特に感じることができました。リモート中心で会社の一体感が欠けやすくなっている状況にぴったりなテーマだったと思います。

  • 当日の進行も滞りなく進み、司会の方の明るさ・さわやかさや、動画編集、企画のすばらしさ、Slackの集計の素早さなどとても良かったです。特にあまり関わることのない方々の素顔や話が聞けたのがとてもよかったです。

  • 内容が豊富かつ進行がスムーズで、あっという間に時間が過ぎました。音楽・映像・美術も素晴らしく、本当にイベントという感じで気分が上がりました。

  • 圧巻でした。素敵な時間をありがとうございました!

■さいごに

ALBERTとしては大きな転換期 での開催となったALBERT DAY 2022でしたが、運営メンバーの試行錯誤、やり遂げる!という強い意志、そして各企画に協力頂いた方々のおかげで無事開催できたことを本当に感謝し、誇りに思います。

このタイミングだからこそ、ALBERT DAYを通じて、会社という大きなチーム全体でこれまでのALBERTの歴史や文化を改めて感じてもらうことができたかなと思います。

変化していく未来に向けて、これからもALBERTのチャレンジは続きます。

The post オンライン全社イベント『ALBERT DAY 2022』を開催しました。 first appeared on ALBERT Official Blog.

RealSense D455による空間認識でmyCobotを操作

$
0
0
  1. Introduction 
現在、先進技術部ではカメラ画像や触覚センサーなどを含むマルチモーダルな強化学習の研究を行っています。その中でシミュレーターでの強化学習結果を実機でも動作させる、いわゆるSim2Realを実現するためには実機のロボットアームとカメラを連携して動作させることは不可欠です。そこで今回はROSを使って6軸ロボットアームのmyCobot(Elephant Robotics社製)とデプスカメラRealSense D455(Intel社製)を連携して動作させるテストを行ったので、その詳細な手順と結果を紹介します。 動作環境:  PC:Ubuntu 20.04, ROS Noetic, Python 3.8.10  ロボットアーム:myCobot 280 M5  デプスカメラ:RealSense D455  このブログでは簡単なプログラム作成や実行方法を書いていますが、ROSやPythonの環境は設定できている前提で話を進めていきます。
  1. myCobotの基本 
購入したmyCobotをPCに繋いでpythonやROSで動かしてみます。  まず、myCobot本体の準備をします。ここで、他にもmyCobotを使ってみた人の解説ブログがあり参考にしたのですが、ファームウェアのアップデート等で使い方が変わっていた部分があり躓きました。この作業をしたのは2021年9月頃でMyStudioのバージョンが3.1.3のときのものになります。おそらく大きな変更はないと思いますが、表示されるものが異なっている場合は公式の手順をご参照ください。 myCobotを動作させるには以下の3つの準備が必要になります。
  • ファームウェアの書き込み 
  • 関節のキャリブレーション 
  • Transponderの起動 
今回のmyCobot 280 M5は土台にM5Stack Basic、アーム先端にATOM Matrix(以降Basic, ATOM)が接続されています。これら2つのモジュールにmyCobotのファームウェアを書き込みます。  まず、USBでPCと接続し、chmodでデバイスへの読み書きを許可します。なお、WindowsやMacでUSBからシリアル通信をする場合は専用のドライバーをインストールする必要があります。
$ sudo chmod 666 /dev/ttyUSB*
次にファームウェア書き込み用のアプリMyStudioをダウンロードします(この記事執筆時の最新版は3.1.4でしたがWindows専用で、Linuxでは3.1.3が利用可能でした)。 Source Codeを解凍してAppImageを実行すると、BasicとATOMでそれぞれ図1, 2のようなGUIが立ち上がります。それぞれの項目を選択してConnectします。
図1: Basicに繋いでMyStudioを起動した場合
図2: ATOMに繋いでMyStudioを起動した場合
MyStudio 3.1.3では図3, 4のような画面が表示されるので、Basicではminirobot、ATOMではAtomMainの最新バージョンをダウンロードし、Flashを選択してファームウェアを書き込みます。Basicで書き込みが完了するとパネルにminirobotの出力が表示されます(Basic, ATOM両方で最新版を書き込まなければ正常に動作しない可能性があるため気を付けてください)。
図3: Basicのファームウェア書き込み画面
図4: ATOMのファームウェア書き込み画面
ファームウェアの書き込みが完了したら次は関節角のキャリブレーションを行います。Basicのパネルを操作しながら関節角の原点を設定します。まずBasicのパネルでCalibrationを選択してOKを押します。
myCobotの各関節には図5のように原点を表す溝が付いているので手動で溝同士が重なるようにします。
図5: myCobotの各関節の原点を表す溝
その状態でBasicのパネルでCalibrate Servoを選択し、NEXTを押していくことでキャリブレーションが完了します。Test Servosを実行すると溝を中心に少しモーターが回転し、正しくキャリブレーションができていることを確認できます。 最後にTransponderを起動するとPCからシリアル通信でmyCobotを操作できるようになります。やることは簡単で、BasicのパネルでTransponderを選択してOKを押すだけです。すると図6のような表示になり、特に何も起こりませんがこれで本体を触るのは以上です。
図6: Transponder起動画面
myCobotについて調べると出てくる情報は少し古いものが多く(おそらく日本での販売開始直後に書かれたものが多いため)、Basic用に書き込むファームウェアがminirobotではなくtransponderなのが落とし穴でした。transponderを書き込んだ場合必要ないのですが、minirobotはTransponder以外の機能も持っている代わりに、パネル操作でTransponderを起動しないとPCからのシリアル通信ができません(※これが記述されている情報はまだ見たことがなく、たまたま起動した状態でシリアル通信したときに動いたことでわかりました)。 Basicのパネルの他のメニューでは、MainControlはBasicでATOMの制御、Informationは各関節が正しく接続されているかを確認します。PCからの動作が上手くいかないときにmyCobot本体の不具合ではないか確認できます。  準備ができたのでPCからmyCobotを操作していきます。 今回はpymycobotを使ってpythonスクリプトから操作する方法と、mycobot_moveitライブラリを使ってROSからMoveIt操作する方法を試したので紹介します。
まず、pymycobotをインストールします。こちらはpipで簡単にインストールできます。
$ pip install pymycobot –upgrade
公式のGithubからソースをダウンロードしてインストールもできます。  ソースからダウンロードするとtestsディレクトリ内にサンプルスクリプトが入っています。ただし、そのままでは動かないので注意が必要です。書き換えの代わりに以下のサンプルを作りました。
# mycobot_control_test.py
#!/usr/bin/env python
import time

from pymycobot.mycobot import MyCobot
from pymycobot.genre import Angle, Coord

if __name__ == "__main__":
port = "/dev/ttyUSB0"
mycobot = MyCobot(port, baudrate="115200", timeout=0.1, debug=False) # baudrate以降はデフォルト値

# 関節角の取得・操作
print("get angles")
print(" degrees: {}\n".format(mycobot.get_angles()))
time.sleep(0.5)

print("get radians")
print(" radians: {}\n".format(mycobot.get_radians()))
time.sleep(0.5)

print("send angles: [0, 0, 0, 0, -90, 0]")
mycobot.send_angles([0, 0, 0, 0, 0, 0], 80)
time.sleep(1.5)
mycobot.send_angles([0, 0, 0, 0, -90, 0], 80)
print(" Is moving: {}\n".format(mycobot.is_moving()))
time.sleep(1.5)

print("send radians: [0, 0, 0, 0, 1.57, 0]\n")
mycobot.send_radians([0, 0, 0, 0, 1.57, 0], 80)
time.sleep(1.5)

print("send angle to joint 4: -90\n")
mycobot.send_angle(Angle.J4.value, -90, 80)
time.sleep(1.5)

# 座標と先端の向きの取得・操作
print("get coordination")
print(" coordination {}\n".format(mycobot.get_coords()))
time.sleep(0.5)

print("send coordination: [50, 50, 300, 0, 0, 0] → [50, 50, 300, 90, 90, 0]\n")
coord_list = [50, 50, 300, 0, 0, 0]
mycobot.send_coords(coord_list, 70, 0)
time.sleep(3.0)
coord_list = [50, 50, 300, 90, 90, 0]
mycobot.send_coords(coord_list, 70, 0)
time.sleep(1.5)

# グリッパーが付いている場合
# print("open gripper")
# mycobot.set_gripper_state(0, 80)
# time.sleep(1.0)
# print("close gripper")
# mycobot.set_gripper_state(1, 80)
# time.sleep(1.0)

time.sleep(1.5)
print("release all servos")
mycobot.release_all_servos()
$ python3 mycobot_control_test.py
mycobotモジュール内のMyCobotクラスのインスタンスを生成し、getterとsetterで状態の確認と変更を行うようになっています。インスタンス生成時は、 
mycobot = MyCobot(port, baudrate="115200", timeout=0.1, debug=False)
で4つの引数を設定します。baudrate以降はデフォルト値を入れています。portはUSBシリアルの通信ポートです。ターミナルで ls /dev/を実行するとPCに接続されているデバイスの一覧を見ることができます。Linuxだと他にシリアル通信をしているUSBポートがなければ /dev/ttyUSB0になっています。MacやWindowsの場合は違うと思うので、適宜確認してください。  ・getterについて  関節角を度数法・弧度法で取得する関数は get_angles(), get_radians()で、返り値は6つの関節角の値が入ったリストになります。  またベースの底面の中心を原点とした座標系でアームの先の座標を取得することができる get_coords()関数も用意されています。返り値は6次元リストで、先端のx, y, z座標(mm)と向きrx, ry, rz(angle)になっています。MoveItを使わなくてもすでに逆運動学が実装されていて便利です。  ※座標系: Basicのパネルを背にそれぞれの正方向は、x: 前、y: 左、z: 上 です。後述するMoveItでは若干ベクトルが異なるため注意が必要です。  ・setterについて  関節角を度数法・弧度法で送信する関数は send_angles(), send_radians()で、引数の設定は二種類あります。  まず、6つの関節すべてを指定して送信する場合は、第一引数にgetterと同様にリスト型に6つのfloat値を入れ、第二引数に関節動作の速さ(int: 0 ~ 100)を入れます。  例: mycobot.send_angles([0, 0, 0, 0, 0, 0], 80)  次に、指定の関節の角度だけを指定して送信する場合は、第一引数に関節角を指定するコード、第二引数に角度の値、第三引数に速さを入れます。  例: mycobot.send_angle(Angle.J4.value, -90, 80)  またgetterと同様に座標指定で動作させることもできます。その場合、第一引数にcoordinationを示す6要素リスト[x, y, z, rx, ry, rz]、第二引数に速さ、第三引数にモードを入れます。モードは0:angular, 1:linearの2種類があり、これらの意味は完全には理解できておらず、モードを変えていくつか動作させてみましたが違いは見られませんでした。 例: mycobot.send_coords([[80, 50, 300, 0, 90, 0], 70, 0)  ※ 速さの単位はソースコードにも詳しく書いていなかったので、必要な場合は変化させながら測定してみるしかないと思います。  ・その他のAPI  一度アームを動作させると、モーターがトルクをかけ続けて現在の状態を維持しようとするため、そのまま放置してしまうとモーターに負荷がかかります。そのため、動作が終了したら関数 release_all_servos()でモーターのトルクを開放しておきましょう。ただし、実行するとすぐに力が抜けてしまうため、アームが高いところから落ちて他のものに当たったりしないように注意してください。 アームが動作中に他の動作を指示するとエラーとなり次の動作に進むようになっています。そこでサンプルスクリプトでは、それぞれの動作が完了するのを待つために間にpython組み込み関数の time.sleep()を使っていますが、whileなどでループできるように関数 is_moving()でモーターが動作中かどうかを取得できます(と思っていたのですがこの関数はバグがあり常に動いている状態を返してしまうようです) 。
この他にも電源のon, offをしたり、LEDの色を変えたり、モーターの状態を確認したりするAPIがありますが今回はアームを動かしてみることを趣旨としているので省略しました。調べたい方は、READMEもしくはGitHubのソースコードに丁寧にそれぞれの関数についてコメントが書かれています。 次にROSからMoveItを使ってmyCobotを操作します。  MyCobotのMoveItはElephant Robotics公式の実装(mycobot_ros)がありインストールできますが、試した時点ではロボットモデルの可視化にバグが残っていたり、ROSと実機との接続が上手くいかなかったりと、なかなかインストールすれば誰でも簡単に使える状態ではありませんでした。 
そこで、有志でMoveItを実装(mycobot_moveit)した方がいらっしゃったのでそちらを利用させていただくことにしました。 インストール方法は上記GitHubのREADMEのPrepararion通りです。
$ cd /src
$ git clone https://github.com/Tiryoh/mycobot_ros
$ git clone https://github.com/nisshan-x/mycobot_moveit
$ rosdep update
$ rosdep install -i –from-paths mycobot_moveit
$ cd ..
$ catkin_make
# setup workspace
$ source devel/setup.bash
インストールを完了して、ワークスペースのセットアップをすると、
$ roslaunch mycobot_moveit mycobot_moveit_control.launch
でMoveItがスタートしRvizのGUIが図7のように起動します。緑の玉をドラッグ&ドロップで動かすと先端位置に対する姿勢が計算され、左下のPlan and Executeボタンを押すことでRvizと実機のロボットが連動して動きます。
図7: mycobot_moveit_control.launchで起動するRviz画面
※モデルと実機が連動しない場合  全ての環境で起こるバグなのかは分かっていないのですが、モデルと実機が連動しないことがあります。モーターの回転方向が逆になることで発生するバグなので、少し面倒ですがモデルと実機を見比べて関節が逆に回転しているところを探してください。  何個目の関節が逆に回転しているか確認できたら、ロボットのモデルを記述するURDFファイルを書き換えます。 /src/mycobot_moveit/urdf/mycobot_urdf_gazebo.urdfにmoveitで使用しているURDFファイルがあり、その中に以下のような関節の情報を定義する記述があります。
mycobot_urdf_gazebo.urdf 
~~
  
        
         
         
        
         
     
~~
arm1 ~ arm6_jointで同じように記述されています。回転軸の方向を設定しているのが <axis xyz="0 0 1"></axis>で逆向きに回転している関節を1 → -1にすると反転させられます。  私の環境では第3関節以外は全て反転していたようです。これがロボットのサーボの個体差なのか別の原因なのかはわかっていないので、わかる方がいらっしゃれば教えていただきたいです。  以上がmyCobotの設定から操作の基本までです。 
  1. RealSense D455の基本 
今回はD455でテストしていますが基本的にD400シリーズは同じように使うことが出来ます。D435iとD455のみIMUセンサーが内蔵されていますが、今回の記事では使用していません(固定状態ではIMUを使うメリットより誤差蓄積のデメリットが目立ったため)。赤外線ステレオカメラを使うD400シリーズと別にLiDARを使うL515などもありますが使用方法は同じです。 また、新しいものが一番性能が良いだろうと思い、エイヤッとD455を買ってもらったのですが、D435iとD455では精度が良い距離や、本体の大きさ、RGBが広角カメラかどうかなどで一長一短な部分があるため自分が使いたい環境と相談して購入するのが良いと思います(それ以前のモデルは基本的に下位互換だと思っていいので値段と性能のトレードオフになります) 。 まず、ソフトウェアのインストールとviewerの基本的な操作です。  RealSenseを動作させるためのライブラリlibrealsenseをインストールします。後述のrealsense_rosもこれがなければ動きません。 linuxでのインストール方法はこちらにドキュメントがあります。Windowsでのインストール方法も同じdocリポジトリ内にあるので必要であれば参照してください。
# サーバーの公開鍵登録
$ sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE || sudo apt-key adv –keyserver hkp://keyserver.ubuntu.com:80 –recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE
# リポジトリの追加
$ sudo add-apt-repository “deb https://librealsense.intel.com/Debian/apt-repo $(lsb_release -cs) main” -u
# ライブラリのインストール
$ sudo apt install librealsense2-dkms librealsense2-utils
# 開発者パッケージもインストール
$ sudo apt install librealsense2-dev librealsense2-dbg
インストールが完了したら、ターミナルで realsense-viewerを実行して確認してみます。上手くいかなかった場合はRealSenseのUSB接続を抜き差し、PC再起動などを試してみてください。 起動に成功すると図8のようなviewerが表示されます。
図8: realsense-viewer
右上の2D | 3Dのボタンで2次元, 3次元にviewerを切り替えられます。また左のStereo Module, RGB Cameraをonにすることで深度情報とRGB情報を見ることができます。  2DではRGBと深度の情報を2次元的に見られます。3Dでは深度推定の赤外線ステレオカメラで推定した点群を、深度のカラーマップやRGBカメラの情報で色付けして、様々な角度から見られます。 また、IMUセンサーを内蔵しているD435i, D455ではMotion Moduleで姿勢情報も取得できます。  次にROSのパッケージrealsense_rosを使ってRvizで点群を見てみます。インストールはaptで可能です。
$ sudo apt install ros-$ROS_DISTRO-realsense2-camera
1つ目のターミナルでRealSenseのカメラを起動して各カメラ情報に加えて色付きの点群を配信、2つ目のターミナルでRvizを起動して可視化してみます。
$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud
$ rviz
図9のように点群を見るために設定をGUIで弄っていきます。
まず、左にある Display パネルの Global Option の Fixed Frame が map になっているのでクリックして camera_link に変えます。
次に Display パネル下部の add ボタンを押すと新しいウィンドウが立ち上がり、Rvizで表示できるROSメッセージの型が列挙されます。その中から rvis グループの中盤にある PointCloud2 を選択してOKを押すと Display パネルに PointCloud2 が追加されます。更にそのグループの中にあるTopic欄右側の空白をクリックすると出てくる /camera/depth/color/points を選択するとRviz上に点群が表示されます。デフォルトでは点群サイズが0.01 mとかなり大きめに設定してあるため点群同士が重なって表示されますが、0.001 mくらいにしてあげることでかなり細かく点群が取得できているのを確認できます。
また、add から今度は TF を選択して追加するとカメラの位置と姿勢(軸方向)を表示できます。デフォルトでRGBカメラの原点、ステレオカメラの原点、がそれぞれ世界座標系と光学座標系で表示されます。(camera_linkはステレオカメラの原点(世界座標系)と同じものになっているようです)
図9: realsense_rosによる点群の可視化
毎回このボタンポチポチ作業をするのは大変なので設定を保存します。
ワーキングスペースに設定保存用のディレクトリconfigを作成して、RvizのfileでSave Config Asを選択、作ったconfigディレクトリに名前を付けて保存します。以降は、
$ rviz -d .rviz
で起動すれば、その設定ファイルを読み込めます。何か変更したら都度Save Configすれば同じファイルを更新できます。 点群とカメラ位置を見るだけなら realsense_viewerで簡単にできますが、ROSを使うことで生データの処理ができます(しかし、個人的にはここが結構つまづきポイントでした)。  ここからはROSのメッセージデータの意味を理解する練習のような内容です。
前節で実行したrs_camera.launch filters:=pointcloudを実行した状態で、別のターミナルで配信されている/camera/depth/color/pointsトピックの生データを見てみます。
$ rostopic echo /camera/depth/color/points
謎の数値配列と最後にis_dense: Trueが出力されます。当然この数値配列が点群のデータで、点群は位置のxyz座標とRGB値で表されることが予想できますが、これを直接読むのは厳しいです。数値を眺めてみると各値は0~255の範囲に収まっていること、周期的に同じような値が出てくることなどの法則は見えます。しかし、ここからどこがxを表していて、どこが赤を表していて……と推測するのは無理があります。
なのでそもそもこのメッセージがどういう型なのかを調べます。
$ rostopic type /camera/depth/color/points
sensor_msgs/PointCloud2
これで、メッセージの型がsensor_msgs/PointCloud2型なのがわかりました。更にROSのドキュメントからこの型の定義を見ると以下のようになっているのがわかります。
Header header # ヘッダー 
uint32 height # データ行数 
uint32 width # データ列数 
PointField[] fields # 1点のデータ構造 
bool    is_bigendian # ビッグエンディアンかどうか 
uint32  point_step   # 1点のバイト数(8bit数値の数) 
uint32  row_step     # 1行のデータ数(= width * point_step) 
uint8[] data         # 生データ(8bitのrow_step * height個のデータ配列) 
bool is_dense        # Trueなら無効なデータはない
点群なので2次元画像と違ってデータの並び順に意味はあるのか?という疑問の通りheight, widthには何の意味もなさそうです(height×widthが点群の数になっていればOK)。他にも別の値から計算できる上に使わなさそうな値まで変数として保持する意味は分かりませんが、このような構造になっています。それぞれの実際の値を見たい場合は、
$ rostopic echo /camera/depth/color/points/<変数名>
とすることでデータの中の一変数だけを出力できます。 例えば、point_stepとfieldをechoすると、
$ rostopic echo /camera/depth/color/points/point_step

20

$ rostopic echo /camera/depth/color/points/fields

name: “x”
offset: 0
datatype: 7
count: 1

name: “y”
offset: 4
datatype: 7
count: 1

name: “z”
offset: 8
datatype: 7
count: 1

name: “rgb”
offset: 16
datatype: 7
count: 1
のように出力されます。point_step = 20なので1点のデータは20 Byteで表されていることがわかり、fieldの内容からその20 Byteがどういう構造になっているかがわかります。ドキュメントからそれぞれの変数の意味は、 name: 表しているデータの名前
offset: 何番目のByteが対応しているか
datatype: 表しているデータの型コード
count: 何個のデータが入っているか  であるとわかります。例えば、x座標に対応するデータは0~3番目で型コードは7(float32に対応)、1つのデータを表します。y, zも同様に処理すればいいことになりますが、RGBも同じ様に表現されています。RGBに対応する16~19番目の値を確認すると、GBRAの順番で16進数の値が入っていました。float32に変換されてしまうと処理するのが厳しそうなのでxyz座標とRGBは分けて処理する必要がありそうです。
データの表現方法がわかったので実際に処理してみます。(次に出てくるスクリプトはもっと賢く速い処理の仕方があると思いますのでアドバイスがあればお願いします)
mycobot_testパッケージの中に、scriptsディレクトリを追加してそこにpythonのスクリプトを追加していきます。
$ cd /src/mycobot_test
$ mkdir scripts
$ cd scripts
$ touch red_point_detection.py
$ touch object_position_search.py
依存関係をCMakeLists.txtとpackage.xmlに書き足します。
# CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS 
# rospyとsensor_msgsモジュールがimportできるように追加 
    rospy sensor_msgs 
) 
catkin_package( 
# ビルドパッケージの追加 
    sensor_msgs 
) 
# 実行ファイルのディレクトリにscriptsを追加 
catkin_install_python(PROGRAMS 
   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}/scripts 
)


  <build>rospy</build> 
  <build>sensor_msgs</build>
以下のred_point_detection.py は点群の中から赤のみを取り出して新しいメッセージを作るスクリプトです。
# red_point_detection.py
#!/usr/bin/env python3 
import time, os, sys, signal, threading 
 
import numpy as np 
 
import rospy 
from sensor_msgs.msg import PointCloud2 
 
class RedPointsDetectionNode(object): 
    def __init__(self): 
        super(RedPointsDetectionNode, self).__init__() 
        self.data = PointCloud2() 
        self.point_step = 20 
        self.R_COL = 18 
        self.G_COL = 17 
        self.B_COL = 16 
        rospy.init_node("red_points_detection_node") 
        rospy.loginfo("red points detection start") 
 
    # Subscriber         
    def sub_pointcloud(self): 
        def callback(data): 
            self.sub_data = data 
        sub = rospy.Subscriber("camera/depth/color/points", PointCloud2, callback = callback) 
        rospy.spin() 
 
    # Publisher 
    def pub_red_pointcloud(self): 
        pub = rospy.Publisher("red_point_cloud", PointCloud2, queue_size = 1) 
        while not rospy.is_shutdown(): 
            pub_data = self.red_point_detection(self.sub_data) 
            pub.publish(pub_data) 
             
    def red_point_detection(sub_data): 
            red_point_data = sub_data 
            red_pointcloud = np.array([d for d in sub_data.data]).reshape(-1, self.point_step) 
            r_flags = red_pointcloud < 180 
            g_flags = red_pointcloud > 150 
            b_flags = red_pointcloud > 150 
            R_under_threshold_row = np.where(r_flags)[0][np.where(np.where(r_flags)[1]==self.R_COL)] 
            G_over_threshold_row = np.where(g_flags)[0][np.where(np.where(g_flags)[1]==self.G_COL)] 
            B_over_threshold_row = np.where(b_flags)[0][np.where(np.where(b_flags)[1]==self.B_COL)] 
            not_red_row = np.unique(np.concatenate([R_under_threshold_row, G_over_threshold_row, B_over_threshold_row])) 
 
            red_pointcloud = np.delete(red_pointcloud, not_red_row, axis=0).ravel().tolist() 
            red_point_data.width = int(len(red_pointcloud) / self.point_step) 
            red_point_data.height = 1 
            red_point_data.row_step = pub_pc2_data.width * self.point_step 
            red_point_data.data = red_pointcloud 
            rospy.loginfo("red pointcloud {}".format(int(len(red_pointcloud) / self.point_step))) 
            return red_point_data 
     
    # node start to subscribe and publish 
    def start_node(self): 
        sub_pointcloud = threading.Thread(target = self.sub_pointcloud) 
        pub_red_pointcloud = threading.Thread(target = self.pub_red_pointcloud) 
 
        sub_pointcloud.setDaemon(True) 
        sub_pointcloud.start() 
        pub_red_pointcloud.setDaemon(True) 
        pub_red_pointcloud.start() 
 
        sub_pointcloud.join() 
        pub_red_pointcloud.join() 
 
if __name__ == "__main__": 
    color_points_detector = ColorPointsDetectionNode() 
    color_points_detector.start_node() 
    pass
subscriberでcamera/depth/color/pointsのデータを読み込み、publisherでそのデータの中から赤い点だけを取り出して配信するという構成です。赤い点は元の点群からRGB値で R &lt; 180, G &gt; 150, B &gt; 150の点を除去する処理をしています。本来は照明条件に依存しやすいRGBを使うよりHSVを使うのがベターですが、今回はPointCloud2のデータを処理しながらHSVに変換するのが大変だったので保留しています(C++ならPCLを使って簡単に変換できたようですが、他の処理を書く大変さに甘えてpythonを使ったのが徒になりました)。
書き終わったらワークスペースに移動して catkin_makeして実行してみます。
$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud
$ rosrun mycobot_test red_point_detection.py
$ rviz -d .rviz
Rvizで PointCloud2 のメッセージに追加された /red_point_cloud を選択すると図10のように抽出した点群を見られます(元の点群をalpha = 0.1にして透過して赤い点を強調しています) 。
図10: red_point_detction.pyによる赤点群の抽出結果
object_position_search.py は取り出した赤い点の座標平均を求めるスクリプトです。
# object_position_search.py
#!/usr/bin/env python3 
import time, os, sys, signal, threading 
 
import numpy as np 
 
import rospy 
from sensor_msgs.msg import PointCloud2 
import sensor_msgs.point_cloud2 as pc2 
from geometry_msgs.msg import Point 
 
class ObjectPositionSearchNode(object): 
    def __init__(self): 
        super(ObjectPositionSearchNode, self).__init__() 
        rospy.init_node("object_position_search_node") 
        rospy.loginfo("object position search start") 
        self.object_position = Point() 
 
    # Subscriber         
    def sub_pointcloud(self): 
        def callback(data): 
            rospy.loginfo("subscribed pointcloud") 
            xyz_generator = pc2.read_points(data, field_names = ("x", "y", "z"), skip_nans=True) 
            xyz_list = [gen for gen in xyz_generator] 
            list_num = len(xyz_list) 
            x = np.array([xyz_list[i][0] for i in range(list_num) if (xyz_list[i][2] < 1.0 and xyz_list[i][2] > -1.0)]) 
            y = np.array([xyz_list[i][1] for i in range(list_num) if (xyz_list[i][2] < 1.0 and xyz_list[i][2] > -1.0)]) 
            z = np.array([xyz_list[i][2] for i in range(list_num) if (xyz_list[i][2] < 1.0 and xyz_list[i][2] > -1.0)]) 
             
            self.object_position.x = np.average(x) 
            self.object_position.y = np.average(y) 
            self.object_position.z = np.average(z) 
 
        sub = rospy.Subscriber("red_point_cloud", PointCloud2, callback = callback) 
        rospy.spin() 
     
    # Publisher 
    def pub_target_position(self): 
        pub = rospy.Publisher("object_position", Point, queue_size=1) 
        while not rospy.is_shutdown(): 
            rospy.loginfo("published object position: {:.5f}, {:.5f}, {:.5f}\n".format(self.object_position.x, self.object_position.y, self.object_position.z)) 
            pub.publish(self.object_position)         
    def start_node(self): 
        sub_pointcloud = threading.Thread(target = self.sub_pointcloud) 
        pub_target_position = threading.Thread(target = self.pub_target_position) 
 
        sub_pointcloud.setDaemon(True) 
        sub_pointcloud.start() 
        pub_target_position.setDaemon(True) 
        pub_target_position.start() 
 
        sub_pointcloud.join() 
        pub_target_position.join() 
 
if __name__ == "__main__": 
    object_position_searcher = ObjectPositionSearchNode() 
    object_position_searcher.start_node() 
    pass
先程のred_point_search.pyを実行した状態で新しくターミナルを立ち上げて実行します。
$ rosrun mycobot_test object_position_search.py
red_point_cloudの座標値の平均を取って配信し、値のログ出力もします。座標値はm単位で、このスクリプトでは1.0 m以内の点を取り出しています。rospy.loginfoで得られた座標をログ出力しているのでターミナルに座標が出力されます。 sensor_msgsライブラリの中にPointCloud2のデータを処理して読むためのpoint_cloud2モジュールがあり座標値を4 Byte → float32の変換しています。中身は簡単な内容ですが、このモジュールの存在になかなかたどり着けず苦労しました。他にも複雑なメッセージデータがあったら付随する処理モジュールがないか調べるのが良さそうです。  RealSenseのセッティングとデータ処理については以上になります。データ処理については用途に応じて処理速度の速い方法を探す(or アルゴリズムを改善する)必要があると思います。 
  1. ROSを使ってmyCobotとRealSense D455の連携 
RealSenseのデータ処理ができたのでいよいよmyCobotと連携して使ってみたいと思います。そこで一番重要になるのがRealSenseのカメラ座標系からmyCobot座標系への変換です。 Rviz上にカメラの座標軸を表示したTF(transform)というのがありましたが、これを理解する必要があります。その名の通り座標変換を記述するもので、ある座標系と他の座標系の間の関係を表します。まずこのTFを何も設定しないとどうなるのか確認してみます。
$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud
$ roslaunch mycobot_moveit mycobot_moveit_control.launch
するとRvizのdisplayパネルに図11のようなWarningが出ていると思います。カメラの各座標系からbase_link(myCobotの原点)へのTransformがありませんというメッセージです。
図11: RealSenseとmyCobotの位置関係を示すTFが不在時のWarning
ということで、カメラからmyCobotへのTF(座標変換)をブロードキャストするパッケージを作ってみます。C++とPythonを行ったり来たりで申し訳ないのですが今回はroscppを使います。まずパッケージを作成します。
$ cd <your_ros_ws_for_MyCobot>/src
$ catkin_create_pkg tf_broadcaster roscpp
$ cd tf_broadcaster
$ touch src/tf_broadcaster.cpp
生成されたtf_broadcaster.cpp, CMakeLists.txt, package.xmlをそれぞれ以下のように書き換えます。なおC++ファイルはクラスでノード作成する練習を兼ねて作ったのでクラスになっていますが、もっと簡単に書くこともできます。
// tf_broadcaster.cpp
#include <ros/ros.h> 
#include <geometry_msgs/TransformStamped.h> 
#include <tf2_ros/static_transform_broadcaster.h> 
#include <tf2_geometry_msgs/tf2_geometry_msgs.h> 
 
class TfBroadcaster 
{ 
public: 
    TfBroadcaster(); 
    ~TfBroadcaster(); 
// Broadcast 
    void BroadcastStaticTfFromCameraToMyCobot(); 
 
private: 
    ros::NodeHandle nh_; 
// TF Broadcaster 
    tf2_ros::StaticTransformBroadcaster static_tf_broadcaster_; 
// constant 
    double PI_ = 3.1419265; 
}; 
 
TfBroadcaster::TfBroadcaster(){} 
TfBroadcaster::~TfBroadcaster(){} 
 
void TfMyCobotBroadcaster::BroadcastStaticTfFromCameraToMyCobot() 
{ 
    geometry_msgs::TransformStamped transformStamped; 
    transformStamped.header.stamp = ros::Time::now(); 
    transformStamped.header.frame_id = "camera_color_frame"; // 親link 
    transformStamped.child_frame_id = "base_link"; // 子link 
  // 平行移動 
    transformStamped.transform.translation.x = -0.3; 
    transformStamped.transform.translation.y = -0.3; 
    transformStamped.transform.translation.z = -0.3; 
    // 回転 
    tf2::Quaternion q; 
    q.setEuler(0, 0, 0); 
    transformStamped.transform.rotation.x = q.x(); 
    transformStamped.transform.rotation.y = q.y(); 
    transformStamped.transform.rotation.z = q.z(); 
    transformStamped.transform.rotation.w = q.w(); 
     
    static_tf_broadcaster_.sendTransform(transformStamped);     
} 
 
int main(int argc, char** argv) 
{ 
    ros::init(argc, argv, "tf_mycobot_broadcaster"); 
    TfMyCobotBroadcaster tf_mycobot_broadcaster; 
    tf_mycobot_broadcaster.BroadcastStaticTfFromCameraToMyCobot(); 
 
    ros::Rate loop_rate(10); 
    while(ros::ok()){ 
        ros::spinOnce(); 
        loop_rate.sleep(); 
    } 
    return 0; 
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2) 
project(tf_broadcaster) 
find_package(catkin REQUIRED COMPONENTS 
  roscpp geometry_msgs tf2_geometry_msgs) 
catkin_package( CATKIN_DEPENDS geometry_msgs tf2_geometry_msgs) 
include_directories(${catkin_INCLUDE_DIRS}) 
add_executable(tf_mycobot_broadcaster src/tf_mycobot_broadcaster.cpp) 
target_link_libraries(tf_mycobot_broadcaster ${catkin_LIBRARIES})
<!-- package.xml -->
<?xml version="1.0"?> 
<package format="2"> 
  <name>tf_broadcaster</name> 
 
  <version>0.0.0</version> 
  <description>The transform broadcaster package</description> 
  <maintainer email="root@todo.todo">root</maintainer> 
  <license>TODO</license> 
 
  <buildtool_depend>catkin</buildtool_depend> 
  <depend>tf2_geometry_msgs</depend> 
  <depend>geometry_msgs</depend> 
</package>
見ての通りですがtransformStampedクラスのインスタンス変数を設定して、そのインスタンスをブロードキャストしています。ブロードキャストの変数型をtf2_ros::StaticTransformBroadcasterにしていますが、今回はカメラとロボットの位置は固定しているため静的なTFを使っています。位置関係が時間変化する場合に使える動的なTFもあるので気になる方は調べてみてください。
ここではまだ位置関係が分かっていないので数値は仮の値になっていますが、これで表示まではできるのでやってみます。また親Linkをcamera_linkではなくcamera_color_frameにしているのは、後者の原点が点群座標系と一致するためです。  catkin_makeしたら、先程と同じようにrs_camera.launchとmycobot_moveit_control.launchを実行して、もう一つのターミナルでtf_broadcasterを実行します。
$ rosrun tf_broadcaster tf_broadcaster
これでカメラとmyCobotのbase_linkの位置関係がブロードキャストされるため、TFのWarningが消えます。この状態で点群を追加すると図12のようになります。当然ですがカメラとmyCobotの位置関係は仮なので、カメラが見ているmyCobotの位置とRvizに表示されるモデルの位置は重なっていません。
図12: TFブロードキャストのテスト
というわけで、次はカメラから見た相対的なロボットの姿勢・位置をキャリブレーションしていきます。
カメラを特定位置に固定することで位置関係を明確にする方法(特にロボットアームの特定位置に固定する場合はかなり簡単)もあると思いますが、今回はマーカーを3点に貼ってロボット座標の単位ベクトルを求め、カメラ座標系との関係を計算する方法で位置関係をキャリブレーションしました。
今までの写真でもすでにマーカーを貼ってある状態で撮影していたので気付いている人もいると思いますが、図13のようにマーカーを配置しています。
図13: myCobotの位置・姿勢キャリブレーション用マーカーの配置
マーカー2,3の中点にmyCobotの原点(底面の中心)が来るようにして、マーカー1はその原点から線分2,3に垂直な方向にあります。
まず、青マーカーの点群を取得するためにred_point_detection.pyを書き換えてblue_point_detection.pyを作ります。抽出するRGBの範囲を書き換えただけなのでここではスクリプトは省略します。  以降、そこから座標変換を求める方法はいろいろあると思いますが、今回は以下の手順で求めました。 
  1. マーカー座標の決定 
    • マーカー点群のサブスクライブ 
    • 点群を3つにクラスタリング(by k-means method) 
  1. 原点と単位ベクトルの決定 
    • マーカー2, 3の中点を原点V_robot 
    • X, Yの単位ベクトルV_X, V_YをそれぞれV_robot→マーカー1, V_robot→マーカー2 
    • Zの単位ベクトルは外積でマーカーのある平面の法線ベクトル 
  1. カメラ姿勢からロボット姿勢への回転をEuler角で作成
    • theta_1 = カメラの水平面に対する仰角 
    • theta_2 = カメラの正面方向の回転角 
    • theta_3 = カメラとロボットのそれぞれの正面方向とのなす角 
  1. 原点をmyCobotの固定台の分(2.7cm)、V_Z方向に平行移動 
※ Euler角で作る回転はどの軸から回転させるかの任意性があるので、使うライブラリによって結果が変わります(順番を任意に設定できるものもあるかもしれません) (わざわざみんながこんなことをしているとは思えないので、二つの座標系の単位ベクトルと原点を渡せばTFに変換してくれるようなライブラリがどこかにあるのではないかと思っています。回転については特異値分解を使って線形代数的に回転行列を求める方法があり、現在はそちらを使っています(「特異値分解 点群レジストレーション」などで検索してみてください)。
以下のスクリプトをscriptsディレクトリに追加しました。
# mycobot_position_calibration.py
#!/usr/bin/env python3 
import time, os, sys, signal, threading 
 
import numpy as np 
 
import rospy 
from sensor_msgs.msg import PointCloud2 
from geometry_msgs.msg import Point 
import sensor_msgs.point_cloud2 as pc2 
 
class MyCobotPositionCalibrationNode(object): 
    def __init__(self): 
        super(MyCobotPositionCalibrationNode, self).__init__() 
        rospy.init_node("mycobot_position_calibration_node") 
        rospy.loginfo("mycobot position calibration start") 
 
    # Subscriber         
    def sub_pointcloud(self): 
        def callback(data): 
            self.data = data 
            rospy.loginfo("subscribed pointcloud") 
            xyz_generator = pc2.read_points(self.data, field_names = ("x", "y", "z"), skip_nans=True) 
            xyz_list = [xyz for xyz in xyz_generator if (abs(xyz[0]) < 0.8 and abs(xyz[1]) < 0.8 and abs(xyz[2]) < 0.8)] 
            xyz_array = np.array(xyz_list) 
 
            if len(xyz_list) > 3: 
                marker_centroids = self.kmeans(3, xyz_array) 
                rospy.loginfo("\n marker positions\n{}".format(marker_centroids)) 
                translation = self.cal_translation(marker_centroids) 
                rospy.loginfo("\n translation\n{}".format(translation)) 
                 
        sub = rospy.Subscriber("blue_point_cloud", PointCloud2, callback = callback) 
        rospy.spin() 
 
    # node start 
    def start_node(self): 
        sub_pointcloud = threading.Thread(target = self.sub_pointcloud) 
        sub_pointcloud.setDaemon(True) 
        sub_pointcloud.start() 
        sub_pointcloud.join() 
     
    # clustering method 
    def kmeans(self, k, X, max_iter=30): # k: cluster num, X: numpy array 
        data_size, n_features = X.shape 
        centroids = X[np.random.choice(data_size, k)] 
        new_centroids = np.zeros((k, n_features)) 
        cluster = np.zeros(data_size) 
        for epoch in range(max_iter): 
            for i in range(data_size): 
                distances = np.sum((centroids - X[i]) ** 2, axis=1) 
                cluster[i] = np.argsort(distances)[0] 
            for j in range(k): 
                new_centroids[j] = X[cluster==j].mean(axis=0) 
            if np.sum(new_centroids == centroids) == k: 
                break 
            centroids = new_centroids 
        max_norm = 0 
        min_norm = 0 
        sorted_centroids = [] 
        for centroid in centroids: 
            norm = centroid[2] 
            if norm > max_norm: 
                sorted_centroids.append(centroid) 
                max_norm = norm 
                if min_norm == 0: 
                    min_norm = sorted_centroids[0][2] 
            else: 
                if norm > min_norm and min_norm != 0: 
                    sorted_centroids.insert(1, centroid) 
                else: 
                    sorted_centroids.insert(0, centroid) 
                    min_norm = norm 
        sorted_centroids = np.array(sorted_centroids) 
 
        return sorted_centroids 
 
    # translation angles calculation 
    ## calculation 
    def cal_translation(self, marker_points): 
        # マーカー1, 2, 3の位置ベクトル 
        a_1, a_2, a_3 = marker_points 
        # カメラからロボットへのベクトル 
        V_robot = self.cal_robot_position_vector(a_2, a_3) 
        # ロボットのXYZ単位ベクトル 
        V_X = (a_2 - V_robot) / (np.linalg.norm(a_2 - V_robot)) 
        V_Y = (a_1 - V_robot) / (np.linalg.norm(a_1 - V_robot)) 
        V_Z = self.cal_normal_vector(marker_points) 
 
        # カメラの水平面に対する仰角 
        theta_1 = - (np.pi/2 - self.cal_subtended_angle(-V_robot, V_Z)) 
        # カメラの正面方向の回転角 
        V_Y_camera = np.array([0, 1, 0]) 
        V_Y_camera_rotated = self.cal_rotate_vector_xaxis(V_Y_camera, -theta_1) 
        theta_2 = - self.cal_subtended_angle(V_Z, -V_Y_camera_rotated) 
        # カメラとロボットのそれぞれの正面方向とのなす角 
        _, V_robot_projected_to_plane = self.cal_vector_projection(V_robot, V_Z) 
        theta_3 = self.cal_subtended_angle(V_Y, V_robot_projected_to_plane) 
        # mycobotの位置を土台の高さ0.027 m, V_Z方向に平行移動 
        V_robot = V_robot + 0.027*V_Z 
 
        return V_robot, theta_1, theta_2, theta_3 
 
 
    ## vector and angle caluculation 
    def cal_robot_position_vector(self, a_2, a_3): 
        return (a_2 + a_3) / 2 
 
    def cal_normal_vector(self, marker_points): 
        a_1 = marker_points[0] 
        a_2 = marker_points[1] 
        a_3 = marker_points[2] 
        A_12 = a_2 - a_1 
        A_13 = a_3 - a_1 
        cross = np.cross(A_13, A_12) 
        return cross / np.linalg.norm(cross) 
 
    def cal_subtended_angle(self, vec_1, vec_2): 
        dot = np.dot(vec_1, vec_2) 
        norm_1 = np.linalg.norm(vec_1) 
        norm_2 = np.linalg.norm(vec_2) 
        return np.arccos( dot / (norm_1 * norm_2) ) 
     
    def cal_vector_projection(self, org_vec, normal_vec): 
        # org_vec: 射影したいベクトル 
        # normal_vec: 射影したい平面の法線ベクトル 
        projected_to_vertical = np.dot(org_vec, normal_vec) * normal_vec 
        projected_to_horizontal = org_vec + projected_to_vertical 
        return projected_to_vertical, projected_to_horizontal 
 
    def cal_rotate_vector_xaxis(self, vec, angle): 
        rotate_mat = np.array([[1, 0, 0], [0, np.cos(angle), np.sin(angle)], [0, -np.sin(angle), np.cos(angle)]]) 
        return vec.dot(rotate_mat) 
 
    def cal_rotate_vector_yaxis(self, vec, angle): 
        rotate_mat = np.array([[np.cos(angle), 0, -np.sin(angle)], [0, 1, 0], [np.sin(angle), 0, np.cos(angle)]]) 
        return vec.dot(rotate_mat) 
 
    def cal_rotate_vector_zaxis(self, vec, angle): 
        rotate_mat = np.array([[np.cos(angle), np.sin(angle), 0], [-np.sin(angle), np.cos(angle), 0], [0, 0, 1]]) 
        return vec.dot(rotate_mat) 
 
if __name__ == "__main__": 
    mycobot_position_calibrator = MyCobotPositionCalibrationNode() 
    mycobot_position_calibrator.start_node() 
 
    pass
今回はカメラとロボットの位置関係から、近いマーカーから順にmarker_1,2,3としていますがカメラを置く場所によって調整する必要があるので注意が必要です。 
ビルドが完了したら、3つのターミナルでカメラ、色探索、キャリブレーションのノードをそれぞれ起動します。
$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud
$ rosrun mycobot_test blue_point_detection.py
$ rosrun mycobot_test mycobot_position_calibration.py
これで、mycobot_position_calibration.pyのターミナルに平行移動 t_x, y, z(m)とEuler角 theta_1, 2, 3(radian)がログ出力されます。点群データ取得やクラスタリングで値がブレるので何回か分の値の平均を取って値を作ります(今回のセッティングでは平行移動、Euler角ともに~1%程度のブレがありました)。
値が取れたら、tf_broadcaster.cppの仮の値だった箇所を書き換えます。
// tf_broadcaster.cpp
~~ 
# それぞれ t_x,y,z と theta_1,_2,_3 に得られた値を入れる 
    transformStamped.transform.translation.x = t_z; 
    transformStamped.transform.translation.y = -t_x; 
    transformStamped.transform.translation.z = -t_y; 
     
    tf2::Quaternion q; 
    q.setEuler(theta_1, theta_2, theta_3); 
~~
今回camera_color_frame から base_linkへのTFを求めていたのですが、点群座標系はcamera_depth_optical_frameでxyzの向きが違っていることに計算してから気付きました(その違いに気付かずしばらく沼りました) そのため、 x = t_z, y = -t_x, z = -t_yとなっています。
書き換えて catkin_makeしたらノードを起動します。
$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud
$ roslaunch mycobot_moveit mycobot_moveit_control.launch
$ rosrun tf_broadcaster tf_broadcaster
すると、カメラとロボットの位置関係が反映されて図14のように点群上のロボットと、Rvizに表示されるロボットモデルを重ねることができます。
図14: キャリブレーションで得た値をTFに設定してブロードキャスト
完全にピッタリとはいきませんが簡単なリーチングや物体ピッキングなら許容できる範囲でのズレに収めることができました。
点群とロボットのモデルを重ねて動かしてみると、myCobotの関節には少し遊びがあり精細な動作をさせるのは難しいことがわかります。
RealSenseから取得した点群座標系をmyCobotの座標系に変換することができたので、物体の位置に向かってmyCobotの先端をリーチングさせてみます。(MoveItを使ってリーチングさせようと思ったのですがC++で沼ってしまったので簡単にpymycobotで動作させるスクリプトにしました)
object_position_serch.pyで求めた赤い物体の座標を表すobject_position topicをサブスクライブして、その座標にmyCobotの先端をリーチングさせます。座標はカメラの光学座標系になっているので、先程求めた平行移動と回転でmyCobot座標系に変換します。以下をscriptsディレクトリに追加しました。
# mycobot_reaching.py
#!/usr/bin/env python3 
import time, os, sys 
 
import numpy as np 
import quaternion 
from pymycobot.mycobot import MyCobot 
 
import rospy 
from geometry_msgs.msg import Point 
from tf.transformations import quaternion_from_euler 
 
class MyCobotReachingNode(object): 
    def __init__(self): 
        super(MyCobotReachingNode, self).__init__() 
        rospy.init_node("mycobot_reaching_node") 
        rospy.loginfo("mycobot reaching start") 
 
        # メンバ変数 
        # mycobot インスタンス 
        port = "/dev/ttyUSB0" 
        self.mycobot = MyCobot(port, baudrate="115200", timeout=0.1, debug=False) 
        # 平行移動と回転 
        # 光学座標系→mycoboto座標系なので4.2節とXYZ軸が違うことに注意 
        self.translation_from_camera_to_mycobot = np.array([t_x, t_y, t_z]) 
        q = quaternion_from_euler(-theta_2, -theta_3, theta_1) 
        self.rotation_from_camera_to_mycobot = quaternion.as_quat_array(q) 
        # subscriber 
        self.sub_point() 
 
    # Subscriber         
    def sub_point(self): 
        def callback(data): 
            rospy.loginfo("subscribed target point") 
            self.mycobot_move(data) 
 
        sub = rospy.Subscriber("object_position", Point, callback = callback) 
        rospy.spin() 
 
    # move mycobot 
    def mycobot_move(self, point_data): 
        # mycobot座標系への変換 
        target_point = np.array([point_data.x, point_data.y, point_data.z]) 
        target_point -= self.translation_from_camera_to_mycobot 
        target_point = quaternion.rotate_vectors(self.rotation_from_camera_to_mycobot, target_point) 
 
        # mm単位のため*1000、手前中心付近にリーチングするためx-20mm, z+40mm 
        coord_list = [target_point[0]*1000-20, -target_point[2]*1000, target_point[1]*1000+40, 0, 90, 0] 
        self.mycobot.send_coords(coord_list, 70, 0) 
        time.sleep(1.5) 
 
if __name__ == "__main__": 
    reaching = MyCobotReachingNode() 
    pass
今回は今まで使ったライブラリと作ったスクリプトを総動員します。
rs_camera.launch, mycobot_moveit_control.launch, tf_broadcaster, red_point_detection.py, object_position_search.py, mycobot_reaching.pyを6つのターミナルでそれぞれ実行してもいいのですが、毎回ターミナルを開いてsetupして……とやっているとデバッグも大変になってしまうので、いい加減自前のlaunchファイルを作成します。
自分のワークスペースに移動してlaunch用のディレクトリとファイルを作成、CMakeLists.txtにlaunchのパスを追加します。
$ cd <your_ros_ws_for_MyCobot>/src/mycobot_test
$ mkdir launch
$ cd launch
$ touch mycobot_reaching.launch
<!-- mycobot_reaching.launch -->
<launch> 
    <include file="$(find mycobot_moveit)/launch/mycobot_moveit_control.launch" /> 
    <include file="$(find realsense2_camera)/launch/rs_camera.launch"> 
        <arg name="filters" value="pointcloud"/> 
    </include> 
 
    <node name="tf_broadcaster" pkg="tf_broadcaster" type="tf_broadcaster" /> 
 
    <node name="color_points_detectior" pkg="mycobot_test" type="red_points_detection.py" output="screen" /> 
    <node name="object_position_searcher" pkg="mycobot_test" type="object_position_search.py" output="screen" /> 
    <node name="mycobot_reaching_node" pkg="mycobot_test" type="mycobot_reaching.py" /> 
</launch>
# CMakeLists.txt
~~
# launchディレクトリの追加 
install(FILES 
  DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch 
) 
~~
launchファイルの構成は簡単でlaunchタグ内で同時に動かしたいnodeとlaunchのファイルを並べてやるだけです。nodeを実行する場合はnodeタグに任意のnode名と、rosrunするときと同じようにパッケージ名と実行ファイル名を書きます。出力をコマンドライン上に表示する場合はoutput=”screen”を追加します。launchファイルの中でlaunchを実行する場合はincludeタグにファイルパスを入れます。catkin_makeをして実行してみます。
$ roslaunch mycobot_test mycobot_reaching.launch
動画1のようにRealSenseが撮影した赤い物体を追跡するようにmyCobotを動かせました。
動画1: mycobot_reachingのテスト
追従するまでにかなりラグがあり、まだ色々な面で勉強不足を感じます。
  1. まとめ 
本記事では、ROSを使って6軸ロボットアームmyCobotとデプスカメラRealSense D455を連携動作させた方法をまとめました。ROSを含めたロボット開発の経験が全くない状態から「こうやったら出来るんじゃないか」を積み重ねてなんとか動かした、という感じでありもっと一般的な方法があるかもしれません。なかなか一からここまでやってみた内容をまとめたブログというのもないと思うので、もしロボットアームやデプスカメラを買ってみたものの使い方がわからない、どう使うか悩んでいる方の参考になれば幸いです。また、ロボット開発経験のある方やデータ処理が得意な方から、ここはもっとこうした方がいいというご指摘も頂ければありがたいです。
今回のmyCobotにシミュレーターで学習した強化学習モデルを適用してピッキングの実験も行ったので後編としてまたブログを書くかもしれません。
ALBERTでは、様々な専門的バックグラウンドを持つリサーチャー・アナリストを募集しています。詳しくは採用ページをご覧ください。

The post RealSense D455による空間認識でmyCobotを操作 first appeared on ALBERT Official Blog.


中学生の企業訪問でリサーチャーとの意見交換を行いました。

$
0
0

2022年11月8日、ALBERTは岡山県立岡山操山中学校から3名の学生の企業訪問を受け入れました。当日は新宿本社に来社いただき、先進技術部のリサーチャーとAI技術に関する意見交換を実施しました。

また今回の企業訪問学習は、同校の東京研修の一環としていくつかのグループに分かれて行われた自主研修で、訪問先の1社として当社を選んでいただきました。
データ活用やAIを扱う企業が多くある中から学生自身でリサーチをして、当社がデータサイエンティスト育成支援事業も行っていたことから、興味を持って連絡をくれたとのことです。

当社メンバーから会社や事業などについてを紹介したのち、学生の皆さんから事前に受けていたAIに関する技術や社会における活用動向などの質問に意見交換をしながら、一つひとつ回答していきました。

【いただいたご質問(一部抜粋)】
・現時点の技術において、サッカーの審判の役割をどこまでAIが担うことが可能か。
・曲のキーやコード進行の類似度を計算するにはどのような方法があるか。
・⼈間が認識しにくい物体を検出するAIを実装するためにどのような⼯夫があるか。​ など

事前にいただいていた質問へ回答すると、さらにその回答に対しても新しい質問が飛び交うなど、AIやデータ活用に対する学生の皆さんの関心の高さが感じられました。

今回の意見交換でデータサイエンティストの仕事やデータ・AI活用に対する理解を深めていただいたことが、これから将来を考えていくきっかけになれば幸いです。


The post 中学生の企業訪問でリサーチャーとの意見交換を行いました。 first appeared on ALBERT Official Blog.

物体追跡の評価指標

$
0
0
こんにちは。先進技術部リサーチャーの田中です。
普段は物体追跡の一種である、複数カメラ複数物体追跡(MTMCT : Multi-Target Multi-Camera Tracking、参考:過去のブログ記事)に取り組んでいます。

物体追跡の可視化結果の例。[1]より引用し改変。
今回は物体追跡の研究やモデル開発に欠かせない評価指標について、近年提案されたHOTA[1, 2]を中心に紹介したいと思います。
早速ですが、最近の私のお気に入りtrackerであるOC-SORT[3]の評価結果を見てみましょう。
なんと9種類もの指標が使われています。たった1つのtrackerを評価するために、これほどたくさんの指標が用いられているのです。

なぜ多くの評価指標が必要なのか

そもそも物体追跡というのは複合的なタスクで、大きくは以下の2つの要素からなります。
  • 動画の各フレームに対して物体を検出
  • 異なるフレームに存在する同じ物体同士を紐付け、同じIDを割り当てる
どちらも完璧にこなすのが最良なのは間違いないですが、完璧な追跡を行うことは現実的には困難です。そこで異なる強みを持つ複数のtrackerに対して、どの手法が優れているかを判断する必要が生じます。

しかしこれは一筋縄ではいきません。例えば以下の2つのtrackerはどちらが優れているでしょうか。
  • 同一物体へのID割り当てに間違いは多いが、全ての物体を検出できている
  • 一時的に検出されないタイミングがあるが、検出された際のID割り当ては完璧である
実はどちらが優れているか(使いやすいか)は場合によって異なります。
例えば人が危険な区域へ侵入しないよう監視したい場合には前者が、要注意人物がどのエリアにいるのかを把握したい場合には後者が有用であることは想像できるかと思います。

つまり評価というのは、使用方法や欲しいモデルが決まって初めて行うことができるものです。上の画像中の指標もそれぞれ目的や測定したい性能が違っており、当然採用する指標によってtrackerの優劣も違ってきます。そしてそれが故に様々な指標での比較を行う必要があるのです。

それでも単一の指標が欲しい

……そうは言っても、やはり指標がいくつもあるとわかりにくいですし、たった1つの最強モデルを決めたくなる気持ちにもなるわけです。
これまではできる限り数を絞った結果として、MOTA[4]とIDF1[5]という2つの評価指標が用いられてきました。それはMOTAとIDF1が物体追跡の構成要素である「物体の検出」「IDの割り当て」のそれぞれを表すような指標であり、この2つを見るだけで各trackerの得意不得意を大まかに把握できていたからです。

今回メインで紹介するHOTAは、
  • 既存の評価指標の問題点を指摘した上で、
  • 「物体の検出」「IDの割り当て」に特化した指標(DetAAssA)を設計し、
  • さらにそれらを統合した、たった1つの指標(HOTA)を提案する
という意欲的な評価指標です。

複合的なタスクである物体追跡を1つの指標で表すためには、なんらかの仮定、つまり設計思想が必要です。その思想を実現するために指標の計算方法を論理的に詰めていく様子や、既存指標の問題点を19の観点で徹底的に論じている様子など、一見の価値がある論文だと思います。お時間のある方、タスクに応じた新しい評価指標を作りたいと思っている方は、このブログで大まかな内容を把握した上で論文を眺めてみることをオススメします。

既存の評価指標  

HOTAの紹介を行う前に、既存の評価指標の概要とその問題点を紹介したいと思います。

共通する用語  

まずは複数の物体追跡指標で共通して用いられる用語について説明します。

IoU(Intersection over Union)  

物体検出(およびその検出結果を用いる物体追跡)では、検出した物体の位置をBBOX(Bounding BOX)で囲うことで表現します。
IoUは2つのBBOX(主に正解BBOXと予測BBOX)がどれほど近いかを表す指標です。その計算方法は2つのBBOXの共通部分の面積を和集合の面積で割ったものであり、図の色付き部分の面積比に相当します。
IoU=0は2つのBBOXに全く重なりがないことを、IoU=1は同じ形のBBOXが同じ位置に存在していることを表します。
IoUはセグメンテーションや3D等に容易に拡張が可能です。実際、MOTS (Multi-Object Tracking and Segmentation) というタスクでは、一般の物体追跡指標内のIoU部分をセグメンテーション用のIoUに置き換えたものが用いられています。

trajectory(軌跡)  

物体追跡を行うためには、同じ物体に対応したBBOXがどれかを特定する必要があります。これは同じ物体を囲んだBBOXが同じIDを持つように、かつ、1つのフレームに同じIDが重複して存在しないように、各BBOXにIDを付与することで実現されます。
ある物体がどのような経路で移動したかを知りたい場合には同じIDを持つBBOXを抽出すればよく、このBBOXを時系列順に並べたものをtrajectoryと呼びます。
この図では2つの正解trajectory(灰色の小さな丸の集合)と2つの予測trajectory(色付きの大きな丸の集合)が示されています。1つ1つの丸はBBOXを表しており、色の違いはIDが異なることを意味します。青色の予測trajectoryのように過不足なく正解trajectoryに追随できることが理想ですが、黄色の予測trajectoryのように途中で予測BBOXが正解BBOXと離れてしまったり、追跡が途切れてしまったりすることもあります。

以下では、このような失敗を定量的に評価するための評価指標について紹介していきます。

MOTA(CLEAR MOT)[4 

MOTA(Multiple Object Tracking Accuracy)は2008年に発表された指標であり、古くから物体追跡の代表的な指標として用いられてきました。
MOTAを提案した論文にはMOTAのコンセプトが複数述べられていますが、その内の1つとして「エラーの種類を特定しやすいこと」が挙げられています。というのもMOTA以前に提案されたものでは、複数の指標が統合されないままに並列に扱われており、しかもそれらが互いに依存していることが多かったためです。

そこでMOTAでは、より根源的で独立した3種類のエラー(FN, FP, IDSW)を定義します。そしてそれらを統合するために、各エラーの発生回数をデータセット全体で集計した上で、正解BBOX数(gt)で割った値を用いて評価を行います。

\displaystyle \begin{aligned} \textrm{MOTA} &= \textrm{1}−\frac{\textrm{|FN|}+\textrm{|FP|}+\textrm{|IDSW|}}{\textrm{|TP|}+\textrm{|FN|}} \\ &= \textrm{1}−\frac{\textrm{|FN|}+\textrm{|FP|}+\textrm{|IDSW|}}{\textrm{|gt|}} \end{aligned}

ここでTPは正解BBOXと予測BBOXのIoUが0.5以上であるもの(IDは考慮しない)、FN/FPは正解/予測BBOXの内TPではないものです。
また、TP, FN, FPで無視されたID割り当てのエラーを集計するための指標がIDSW (ID SWitch)です。これは各正解trajectoryに対する予測IDが切り替わった回数を表しています。

※より厳密に表現すると、「正解BBOXの予測ID」をそれと重なった予測BBOXのIDとするとき、各正解trajectoryを構成する正解BBOXの内で予測IDを持つものを時系列順に見ていき、予測IDが切り替わった回数となります。

MOTAはこれら3種類のエラーを全て対等に扱うという単純な方法で集約しています。
しかし評価結果の表[3](再掲)をもう一度見てみましょう。
IDSW(表ではIDs)とその他の2つを比べると、FPはIDSWの十倍程度、さらにFNはIDSWの数十倍の値を持っています。つまり(少なくとも現代のtrackerにおいては)IDSWという「IDの割り当て」に関するエラーがMOTAに与える影響は非常に小さく、ほとんどFN, FPといった「物体の検出」に関するエラーのみを測定する指標となってしまっているのです。

もちろんFN, FPは純粋な物体検出の精度を表しているわけではありません。物体検出で検出されたBBOXからtrajectoryを構成できそうなものを抽出した結果として得られる値ですので、そこに追跡の要素が入っていることは間違いありません。しかしID割り当ての精度を正当に評価できているかについては疑問が残ります。

※ちなみに上の議論では「IDSWが小さいのは現代trackerのID割り当て性能が非常に高いため」という可能性を排除できていません。しかしIDSWは「IDが切り替わった回数そのもの」であるのに対し、FN, FPは「ミスが起こった回数×そのミスが継続しているフレーム数」のような値となっており、本来同列に扱うべき量ではないというのが個人的な見解です。

※さらにFPがFNより小さいのは、追跡対象が人間という特徴的な形をしているものであり誤検出(FP)が比較的発生しにくいこと、一方で人間同士が重なることによる見逃し(FN)は容易に発生しうることが原因だと思われます。HOTA論文には「MOTAではFNとFPが対称ではないために、MOTAに合わせてチューニングするとFPが小さくなりがちである」という興味深い主張がありますが、OC-SORTではHOTAも評価指標として用いているためそれは根拠にはなりません。

IDF1(IDentification scores)[5 

IDF1(IDentification F1 score)は2016年に発表された評価指標です。
私たちも取り組んでいる、複数カメラ複数物体追跡のための評価指標として提案されましたが、単一カメラでの物体追跡にも広く用いられています。

IDF1のコンセプトは「誰が、いつ、どこにいるか」の精度を測定することです。
そのためまずは動画に対する予測を行い、正解trajectoryと予測trajectoryのマッチングを行います。これはある人物(正解trajectory)が「誰」なのかを特定する(予測IDを割り当てる)作業と言い換えることもできます。

そして「いつ、どこにいるのか」を評価するためにIDTP, IDFN, IDFPを定義し、IDF1を得ます(それぞれTP, FN, FP, F1に対応)。

\displaystyle \textrm{IDF1}=\frac{\textrm{2|IDTP|}}{\textrm{2|IDTP|}+\textrm{|IDFN|}+\textrm{|IDFP|}}

ここでIDTPは「誰が、いつ、どこにいるか」を全て正しく予測できたBBOXで、正解BBOXと予測BBOXのIoUが0.5以上であり、さらにIDが正しいもの(それらを含むtrajectory同士がマッチングされているもの)に当たります。IDFN/IDFPはそれぞれ正解/予測trajectoryに含まれるBBOXのうちIDTPではないもの、つまりマッチングされたが位置が不正確なBBOXやそもそもマッチングされていないtrajectoryに含まれるBBOXです。これらの個数はデータセット全体で集計されます。
IDTPの定義さえわかれば、残りのIDFN, IDFP, IDF1の考え方は一般的なものと同じなので理解はしやすいのではないかと思います。

※正解trajectoryと予測trajectoryマッチングはIDTPを最大化するように行われます。つまり「いつ、どこにいるか」の精度が最も高くなるように「誰」を選ぶ(=IDを割り当てる)というのがより正確な表現となります。

上記の定義を見ると「物体の検出」と「IDの割り当て」の両方の精度を測定できそうな気がしますが、実はIDF1は「物体の検出」に関しては弱点があることが知られています。例えば図のような状況を考えてみましょう。
左の例では正解BBOXの内最初の3つの予測に成功していますが、残りの2つについては検出すらできていません。一方右の例では、最後の2つの検出には成功しているものの、誤ったIDを割り当ててしまっています。物体追跡が検出とID割り当てからなると考える場合、検出に成功した右の例は左の例と同等以上の評価を得るべきですが、IDF1では左の方が高く評価されます。これはIDF1が検出に関して単調でないことを示す例であり、IDF1が物体の検出に関する評価を正当に行えないことの証拠とされています。

※ちなみに上で述べていることはあくまで評価指標の特性の話であり、ユースケースによっては単調性の有無が問題にならない場合もあります。例えば多少の見逃しを許容してでも誤った検出を行いたくない場合にはIDF1は適していることが考えられます。

新進気鋭の評価指標:HOTA[1, 2 

それでは本題であるHOTA(Higher Order Tracking Accuracy)の紹介を行いたいと思います。
HOTAは2021年に発表された新しい評価指標です。HOTAのコンセプトは、評価指標としての望ましい性質であるエラーの種類の分離性・対称性・単調性を持った指標であることです。

エラーの種類の分離を行いやすくするために、HOTAでは「物体の検出」「IDの割り当て」に特化した指標(DetAAssA)を設計し、それらを組み合わせることでHOTAを得ます。そして単一の指標が欲しければHOTAを参照し、個別の性能を測定したければDetA, AssAを始めとしたサブメトリクスを参照することで、様々な目的に合致した性能評価を行えることが特長の1つとなっています。

「物体の検出」に関する評価指標:DetA  

HOTAのサブメトリクスであるDetA(Detection Accuracy score)は「物体の検出」に関する評価指標です。
DetAではMOTAと似た考え方でTP, FN, FPを定義します。唯一の違いは、IoUの閾値を変数αとして与えるところです(MOTAやIDF1では閾値は0.5で固定)。つまりTPは正解BBOXと予測BBOXのIoUが閾値α以上であるもの(IDは考慮しない)、FN/FPは正解/予測BBOXの内TPではないものです。これらの個数はデータセット全体で集計され、後段の計算に用いられます。

DetAは以下のように定義されます。添字のαは前述の閾値を表しています。

\displaystyle \textrm{DetA}_\alpha = \frac{\textrm{|TP}_\alpha\textrm{|}}{\textrm{|TP}_\alpha\textrm{|}+\textrm{|FN}_\alpha\textrm{|}+\textrm{|FP}_\alpha\textrm{|}}

MOTAは分母にgt = TP + FNが存在することからも分かるとおり、FNとFPに対して対称ではありません。一方DetAや、後述のAssA, HOTAは全て対称性を持つため、FNとFPに対して同じペナルティを与えることができます。

「IDの割り当て」に関する評価指標:AssA  

HOTAのサブメトリクスであるAssA(Association Accuracy score)は「IDの割り当て」に関する評価指標です。
AssAの定義は以下の通りです。TPや添字の閾値αはDetAで定義されたものと同一です。

\displaystyle \begin{aligned} \textrm{AssA}_\alpha &= \frac{\textrm{1}}{\textrm{|TP}_\alpha\textrm{|}}\sum_{c \in \textrm{TP}_\alpha} \mathcal{A}_\alpha(c) \\ {\rm ただし} \mathcal{A}_\alpha(c) &= \frac{\textrm{|TPA}_\alpha\textrm{(c)|}}{\textrm{|TPA}_\alpha\textrm{(c)|}+\textrm{|FNA}_\alpha\textrm{(c)|}+\textrm{|FPA}_\alpha\textrm{(c)|}} \end{aligned}

これまでに紹介してきた指標とは式の形が異なっています。
この式は\mathcal{A}という中間的な指標を計算した上で、それをc∈TP で平均することを意味しています。ここでcはTPとして判定された、つまりIoUが閾値α以上である正解BBOXと予測BBOXのペアを表しており、\mathcal{A}はcを含む正解trajectoryと予測trajectoryがどれほど一致しているかを表す指標です。

また2行目の\mathcal{A}の定義に注目すると、TPA(c)は正解BBOXと予測BBOXのIoUが閾値α以上で、それらが共にcと同じIDを持つ(つまりcと同じtrajectoryに含まれる)もの、FNA(c)/FPA(c)はcと同じIDを持つ正解/予測BBOXのうちTPA(c)ではないものです。

TPA(c)の定義が、IDF1の構成要素であるIDTPの定義と似ていることに気づかれたかもしれません。確かにAssAとIDF1は似た指標ではありますが、それぞれのIDの割り当て手法には大きな違いがあります。IDF1では正解trajectoryと予測trajectoryに対してマッチングを行い、ただ1つの正しいID割り当てを定めていました。一方AssAではID割り当てを1つに定めません。AssAの定義式の1行目は、各cそれぞれが正しいID割り当てだと仮定した時の評価値\mathcal{A}を個別に計算し、それらを平均することを意味しているのです。

※実は\mathcal{A}(c)やその構成要素は全て、cを含む正解trajectory1つと予測trajectory1つに対してのみ集計されるローカルなものです。従ってデータセット全体に対する指標であるAssAを得るためには何らかの手法で\mathcal{A}(c)を集約する必要があります。AssAではTPに関する平均が採用されていますが、その理由は次節で紹介します(一言で言うと、HOTA全体の単調性を担保するため)。

AssAの算出方法について、この画像を例に具体的に確認してみましょう。
まずはTPである全てのペアについて\mathcal{A}を計算します。TPは全部で5つありますが、青色と灰色が正しいペアだと仮定した場合は{TPA, FNA, FPA} = {3, 2, 1}、黄色と灰色が正しいペアだと仮定した場合は{TPA, FNA, FPA} = {2, 3, 1}となり、結果的に得られる\mathcal{A}は2種類しかありません。
AssAはTPである全てのペアについて\mathcal{A}を平均したものですが、これは得られた2種類の\mathcal{A}をそれぞれのTPAの数に応じて加重平均することに相当するため、図のように計算することができます。

IDF1ではたった1つのマッチング(この図の場合は青色が採用される)のみが採用されていたため、選ばれなかった予測trajectory(黄色)の予測の精度は評価に一切反映されませんでした。しかしHOTA(AssA)ではどちらの予測も評価に含まれています。このことによって、trackerの細かな精度向上を捉えやすくなっています。

ちなみにIDF1と同様に、AssAは検出に対して単調ではありません。例えばこの図の例では、黄色の予測がない方がAssAは高い値(1/2)を取ります。AssAは「IDの割り当て」に特化した指標であるため当然ではありますが、誤解がないようご注意ください。

HOTAの算出方法  

HOTAα は DetAα と AssAα の幾何平均を取ることで得られます。

\displaystyle \begin{aligned} \textrm{HOTA}_\alpha &= \sqrt{ \textrm{DetA}_\alpha \cdot \textrm{AssA}_\alpha} \\ &= \sqrt{ \frac{\textrm{|TP}_\alpha\textrm{|}}{\textrm{|TP}_\alpha\textrm{|}+\textrm{|FN}_\alpha\textrm{|}+\textrm{|FP}_\alpha\textrm{|}} \cdot \frac{\textrm{1}}{\textrm{|TP}_\alpha\textrm{|}} \sum_{c \in \textrm{TP}\alpha} \mathcal{A}_\alpha(c)} \\ &= \sqrt{ \frac{\sum_{c \in \textrm{TP}_\alpha} \mathcal{A}_\alpha(c)}{\textrm{|TP}_\alpha\textrm{|}+\textrm{|FN}_\alpha\textrm{|}+\textrm{|FP}_\alpha\textrm{|}}} \end{aligned}

最終的な式の根号の中に注目すると、DetAの分子の各TPを、それぞれのID割り当てに関する精度\mathcal{A}で重み付けしたものとなっています。
実はAssAはこの式が成立するように定義されています。なぜならこの定式化のおかげで、これまで問題となっていた検出に関する単調性が保証されるからです。例えば元々見逃されていた(FNであった)BBOXを、新たな予想BBOXによって検出できた(TPとできた)場合について考えてみましょう。この場合、分母の合計値は変化しない一方、分子については0より大きな値を持つ\mathcal{A}が追加されるため、HOTAは増加することがわかります。

そして最後に、 正解/予測BBOXのIoUの閾値αで積分を行います。

\displaystyle \begin{aligned} \textrm{HOTA} &= \int_\textrm{0}^\textrm{1} \textrm{HOTA}_\alpha d \alpha \\ &\approx \frac{\textrm{1}}{\textrm{19}} \sum_{\alpha \in \left\{ \ \substack{\textrm{0.05, 0.10,} \\ \textrm{…, 0.95}} \ \right\} } \textrm{HOTA}_\alpha \end{aligned}

これは、いままでは考慮していなかったBBOXの位置特定精度を評価指標に組み込むことに相当します。既存の評価指標でいうと、MOTAと同時に提案されたMOTP(Multiple Object Tracking Precision)[4]という指標が扱っているエラーです。

※ちなみに最初に提示した評価結果の表に存在するAssAはAssAαを閾値αで積分したもの、またAssR(Association Recall)はAssAと同じ考え方で定義されたRecall、つまり AssR_ \alpha = \frac{\textrm{1}}{\textrm{|TP}_ \alpha\textrm{|}} \sum_{c \in \textrm{TP}_ \alpha} \frac{ \textrm{|TPA}_ \alpha \textrm{(c)|} }{ \textrm{|TPA}_ \alpha\textrm{(c)|} + \textrm{|FNA}_ \alpha\textrm{(c)|} }を閾値αで積分したものです。このようにHOTAでは様々なサブメトリクスを自然に定義可能であり、具体的なユースケースが決まっていれば、それに適した指標で評価をすることもできます。

HOTA“の”評価  

最後に「HOTAによる評価結果」の評価について紹介します。
ここまでで触れてきた通り、HOTAは評価指標として望ましい性質を複数持ち合わせた指標です。ただしどれだけ理論的に望ましい性質を持っていても、人間の感覚と異なる評価結果であれば使われることはありません。実際MOTAが長年使われてきたのも、人間の考える「良い追跡結果」に対して高い評価結果を与えられるからだという研究[6]も存在しています。

そこでHOTA論文では、HOTAとMOTA, IDF1の中でどの評価指標が最も人間の感覚と近いかという調査を行なっています(以下の2つの図は[1]より引用)。
具体的にはある場面に対して2つのtrackerで予測を行った上で、各指標がどちらの予測を高く評価したかを記録しておきます。高く評価されたtrackerが指標によって異なる場合、それは評価指標の意見が割れた場面だと言えます。そこで評価が割れた場面を上図のように人間に評価させることで、人間の感覚に近い判断を下した指標がどちらなのかを判定することができます。
評価指標の評価結果がこちらの円グラフです。内側のグラフは人間がどちらかの評価指標と同じ判断を下した場面の割合を表しており、外側のグラフは人間がどちらの予測結果も同程度の性能だとした場面を含んだ割合になっています。MOTA, IDF1と比較して、HOTAはより人間の感覚と合致する回数が多いことが示されています。

まとめ  

HOTAは以下のような特長を持つ指標です。
  • 「物体の検出」「IDの割り当て」「BBOXの位置特定」に関する精度評価をたった1つに組み込んでいる
  • エラーの種類の分離性、単調性、対称性といった評価指標としての望ましい性質を持つ
  • サブメトリクスを活用することで、目的に応じた性能評価を行うこともできる
HOTAを提案した論文では、既存の評価指標の問題点を解決していることを理論的に示すだけでなく、その評価結果が人間の感覚と近いことを実験的に確かめてもいます。

また本ブログでは触れませんでしたが、HOTAはその定義の明快さから容易に拡張が可能です。論文[1]では複数カメラ複数物体追跡や未知物体の追跡など、特殊な物体追跡のための評価指標も同時に提案されています。実際、KITTI[7], Open World Tracking[8], MOT Challenge[9]など、HOTAを評価指標として採用するベンチマークは年々増加しており、今後も主流となることが予想されます。 最後になりますが、ALBERTには様々な専門的バックグラウンドを持つリサーチャー・アナリストがおります。技術に関する疑問やビジネスに関するご相談など、お気軽にお問い合わせください。

References  

[1] Jonathon Luiten, A.O. & Leibe, B. HOTA: A Higher Order Metric for Evaluating Multi-Object Tracking. International Journal of Computer Vision, 2020.
[2] HOTAの著者による解説ブログ:https://autonomousvision.github.io/hota-metrics/
[3] J. Cao, X. Weng, R. Khirodkar, J. Pang, and K. Kitani.Observation-centric sort: Rethinking sort for robust multiobject tracking. arXiv preprint arXiv:2203.14360, 2022.
[4] Bernardin, K. & Stiefelhagen, R. Evaluating Multiple Object Tracking Performance: The CLEAR MOT Metrics. Image and Video Processing, 2008(1):1-10, 2008.
[5] Ristani, E., Solera, F., Zou, R., Cucchiara, R. & Tomasi, C. Performance Measures and a Data Set for Multi-Target, Multi-Camera Tracking. In ECCV workshop on Benchmarking Multi-Target Tracking, 2016.
[6] Leal-Taixé, L., Milan, A., Schindler, K., Cremers, D., Reid, I., Roth, S.: Tracking the trackers: an analysis of the state of the art in multiple object tracking. arXiv preprint arXiv:1704.02781 2017.
[7] https://www.cvlibs.net/datasets/kitti/eval_tracking.php
[8] https://openworldtracking.github.io/
[9] https://motchallenge.net/

The post 物体追跡の評価指標 first appeared on ALBERT Official Blog.

エンジニアブログの過去の投稿はこちらをご覧ください

Redis Cluster の構築と利用(Redis 3.0.0)

$
0
0

みなさまこんにちは。池内です。

Redis 3.0.0 から正式な機能として盛り込まれたRedis Clusterの構築と基本的な動作について紹介します。

※ 期せずして本日 LINEさんの事例 LINEの100億超/日メッセージを支えるRedis・HBaseのスケールアウト・アップ戦略(A-5) #linedevday – Togetterまとめ が話題になっていますが、合計48TBものメモリサイズで運用しているようです。凄いですね。

Redis Cluster とは

  • 疑似的なマルチマスタ構成
  • 複数ノードでデータをシャーディングできる
  • スレーブ構成を採用すれば耐障害性の向上も可能

概ね上記のような内容です。マルチマスタを「疑似的」としているのは、実際にデータが各ノードに伝播しているわけではないからです。Redis Clusterは、あるレコードをどのノードに保存するかを把握しておき、ノード間でリダイレクトすることによって、どのノードから接続しても指定するデータにたどり着けるというアーキテクチャを採用しています。この記事では便宜上マルチマスタと表記します。

Redis Cluster マスタのみの構築

下記のノードが存在するとします。(単一のサーバーホストにポート違いで複数台Redisを起動する方法がよく紹介されますが、今回の手順では、実際にサーバーが複数台存在する環境を想定しています)

Host Private IP
redis1 192.168.10.212
redis2 192.168.10.213
redis3 192.168.10.214
redis4 192.168.10.215

通常の手順で各ホストにRedisをインストールした後、redis.conf に下記の設定を記述します。

redis.conf の設定

port 16379
cluster-enabled yes
cluster-config-file /etc/redis/nodes.conf
cluster-node-timeout 5000
appendonly yes

設定ファイルの場所や使用するPort番号は適時読み替えて下さい。

Cluster の作成

redis-3.0.0.tar.gz を解凍すると、クラスタ構築用のRubyスクリプト redis-trib.rb が入っているのでこれを利用します。

$ /usr/local/src/redis-3.0.0/src/redis-trib.rb create 192.168.10.212:16379 192.168.10.213:16379 192.168.10.214:16379 192.168.10.215:16379

以上が正常に実行されれば、Cluster の作成は完了です。ログイン時は下記の通りオプションを付与します。

$ redis-cli -c -p 16379

この構成では、4ノード全てがマスタになっています。マルチマスタが実現されているので、どのノードから SET しても、全ノードからGETすることができます。

実際にコマンドを実行すると、下記のように表示されることがあります。

192.168.10.212:16379> set key1 value1
-> Redirected to slot [9189] located at 192.168.10.213:16379
OK

redis1 から接続しましたが、redis2にリダイレクトされ、結果 Key: key1, Value: value1 のレコードは redis2 に保存されます。

この点の解説は多く存在するのでここまでにします。

Redis Cluster マスタ・スレーブの構築

上述の手順では、4つのノード全てがマスタの役割を持っていました。この場合、データが冗長化して保存されている訳ではありません。従ってノードがクラッシュすると、そのノードのデータがロストする可能性があります。また、各ノードの死活監視はRedis Cluster自身が行っていますが、ノードが fail と判定されると、そのままでは「 (error) CLUSTERDOWN The cluster is down」となり、読み書きが出来なくなります。

そこで、Redis Clusterの可用性をあげるためにマスタ・スレーブ構成で構築します。

$ /usr/local/src/redis-3.0.0/src/redis-trib.rb create --replicas 1 192.168.10.212:16379 192.168.10.213:16379 192.168.10.214:16379 192.168.10.215:16379

同様に、 redis-trrib.rv スクリプトで create を行います。このとき、 –replicas 1 オプションを付与します。しかし、下記のエラーが発生します。

*** ERROR: Invalid configuration for cluster creation.
*** Redis Cluster requires at least 3 master nodes.
*** This is not possible with 4 nodes and 1 replicas per node.
*** At least 6 nodes are required.

Redisクラスタはマスタが最低3ノード必要で、各マスタに1つのスレーブが対応付くため、結果的に6ノードが必要になります。そこで、サーバーを2台追加します。このとき設定ファイルは変更する必要がありません。

Cluster の作成

$ /usr/local/src/redis-3.0.0/src/redis-trib.rb create --replicas 1 192.168.10.212:16379 192.168.10.213:16379 192.168.10.214:16379 192.168.10.215:16379 192.168.10.216:16379 192.168.10.217:16379

この結果、以下の状態になったとします。

Host Private IP Role
redis1 192.168.10.212 Master1
redis2 192.168.10.213 Master2
redis3 192.168.10.214 Master3
redis4 192.168.10.215 Slave of Master1
redis5 192.168.10.216 Slave of Master2
redis6 192.168.10.217 Slave of Master3

障害時の挙動

ノードの障害時は、以下のような挙動をとります。

  • redis6 がダウンした場合、redis6はSlaveであるため、そのままClusterの動作を続行します。その後 redis6 が復帰した場合、自動でClusterに加えられます。
  • redis3 がダウンした場合、redis3 のスレーブである redis6 がマスタに昇格します。redis3 が復帰した場合、今度は redis3 が redis 6のスレーブとしてClusterに参加します。
  • redis1 がダウンした場合、redis1 のスレーブである redis4 がマスタに昇格します。続いて redis4がダウンした場合、 (error) CLUSTERDOWN The cluster is down となり動作を続行できません。その後 redis1 または redis4が復帰した場合、マスタとしてClusterに参加します。

全体で6ノード稼働している場合、2ノードの同時停止でCluster全体が機能不全に陥る可能性があります(反対に最大で、3ノードの同時停止まで耐えられます)。AWSで構築する場合、マスタとスレーブのAZを分けるなどの設計が求められます。

なお、各マスタに紐尽くスレーブは1ノードよりも多くすることもできます。

利用ノードの固定

ノードの固定について紹介します。

Redis Clusterでは、レコードが各ノードに散らばって保存されます。しかし、SET型で集合演算を行う際に、集合演算対象のレコードが同一のノードに存在している必要があるという制約が存在します。このときに利用するのが Keys hash tags です。

SET foo-var0001 vlaue
SET foo-var0002 vlaue

どちらかのSETで、リダイレクトが発生する状況であると仮定します。その際、共通利用できるキーの文字列部分を {} で囲うことで、ハッシュとして利用できます。

set {foo}-var0001 vlaue
set {foo}-var0002 vlaue

この結果、{foo}-var0001 と {foo}-var0002 を同一ノードに保存するこができます。

MSET などの Multiple Keys についての注意

Redis Clusterでは、MSETなどの利用にも注意が必要です。

127.0.0.1:16379> MSET key1 value1 key2 value2
(error) CROSSSLOT Keys in request don't hash to the same slot
127.0.0.1:16379> MSET {key}1 value1 {key}2 value2
-> Redirected to slot [12539] located at 192.168.10.214:16379
OK

上記の通り、通常通りMSETを実行するとエラーになります。 hash tags を利用することによってMSETが実行可能になります。MGETも同様です。

クライアントについて

Redis Clusterを利用するには、対応したクライアントライブラリを利用します。RubyやPythonの対応クライアントは公式ドキュメントでも紹介されています。

いずれも、非対応ライブラリとの差分はインスタンスを作成する際にRedisのノード情報をリストで渡す箇所程度のようです。

まとめ

  • マスタノードだけでは可用性の向上には繋がらない点に注意して利用します。
  • マスタ・スレーブは可用性の向上に繋がりますが、最小6台構成を取る必要があります。Fail Overの挙動を把握しておく必要があります。
  • レコードが同一ノード上にないと問題の発生する処理(コマンド)があります。ノードを固定することもできますが、データの偏りに気を配りましょう。

Redis Sentinelのように司令塔を配置しなくてもよいため、単純な揮発性のデータストアとして利用するにはかなり気軽に運用できそうです。ただし、集合演算をする場合やもう少しシビアな運用を迫られるケースでは、Redis Clusterの特性をよく理解しておく必要があることが分かりました。

参考文献

最後になりますが、ALBERTでは、データサイエンティストを積極募集しています。
ぜひ採用ページをご覧ください。

The post Redis Cluster の構築と利用(Redis 3.0.0) first appeared on ALBERT Official Blog.

神経科学からマーケティングへ…違いと意外な類似

$
0
0

初めまして、この3月からALBERTにジョインしました最上嗣生と申します。

これまでは理化学研究所脳科学総合研究センターで神経科学、いわゆる「脳研究」をやっていました。特に高等動物の高次視覚野が物体の価値の評価へ寄与をしている様子を調べていました。

さて、そのような研究をしていたものが、ALBERTに加わってからはマーケティング領域の分析をしているわけです。びっくりするほどの違いだと思いますよね?そうです、まずは違いからお話しします。(ほかの方の記事のような実用的な記事は、次回以降にご期待ください。)

研究と今の仕事の一番の違いは仕事のスピードで、これには目を回しました。もちろん人間にできないことをやっているわけはないので、ちゃんと理由があります。研究者にはできないくらい高速で仕事ができる秘密は、「細かいことはいいので結果重視」ということだと思います。研究者の世界では、とにかく細かいことに突っ込まれます。例えばの話ですが、説明変数を30個選んだとします。20個に減らしても60個に増やしてもあまり結果が変わらないことは経験上、そして試してみてわかっています。それでも、学問の世界ではなぜ30個なのかねちっこく突っ込まれます。答えなければ論文が採択されません。1個刻みで全部調べて最良であることをいい、その理論的な理由もつけたりくらいしないと論文査読者は納得しません。それはやればできますが、倍時間がかかります。しかもあらゆる事柄について同様の突っ込みがなされます。一方、こちらの世界ではそんなことは聞かれなかったことに拍子抜けと驚きを感じました。要するに、役に立つかどうかが問題なのでしょう。

次の違いは、変数がなんだかわからないということです。それが何を意味しているのか、空欄は単なる欠測なのか、それとも何か別の意味なのか。欠測は偶然発生するのか。これまで実験科学者をやっていたときは、変数は自分で作るものでしたから、意味が分からないということはありませんでした。一方、ALBERTに入ってからマーケティングの分析をやってみると、まず変数がなんだかわかりません。お客様に聞いてわかるとも限りません。変数自身から調べたりします。
また、こちらではデータは分析の都合に合わせて作られるわけではないので、是非なくてはならないと思う変数がなかったり、要らない変数がたくさんあったりします。要らないものは捨てればいいですが、要るものがないのは苦しいものです。ほかの変数を組み合わせて推定したりします。
しかし実は、実験の最初の計画でないアドホック解析のために変数が足りないことは(厳密にはよくないことではあるけど)神経科学のような未知の要素の多い科学分野ではよくあることです。だからこそ適応できたといえます。

最後のちがいは心構えです。こちらに来てから、お客様への善意ということを意識するようになりました。特に直接のクライアントよりさらにそのお客様、消費者のことをよく考えます。この仕事の結果、ちょっとにやりとしたり嬉しかったりする人が増えるといいと思います。実験室ではもちろんそんなことは考えるはずもありませんでした。

さて、一方脳研究と、今の仕事とで変わらないことも多くあります。

意外と解析技術は変わりません。簡単なt検定から始まって、サポートベクトルマシンやニューラルネットのような機械学習まで解析手法として使うところは同じです。(科学研究は現実を冷静に認識するのが目的ですから、ニューラルネットのような多数の安定状態をもつようなものを私自身は規律として避けていました。複数の安定状態というのはいわば主観のようなものですから。しかし実際は気軽にそういう解析手法を使う人も多かったので、私も馴染んではいました。)

一方、解析技術というだけではなく、行き着く先というのも意外と共通です。
と、いうのは、脳というのは何のためにあるかというと、つまり外界について解析して、その結果から有利な行動を選ぶためにあるわけです。
したがって、脳の働きとは、ほとんど今我々がやっているマーケティングの解析と同じものです。いわば我々の仕事はクライアントの脳になることですから。(決断を代替することはできませんが、視覚野となって市場を「見て」、前頭葉となって仮説を立て、ドーパミン系になって何かをした時の利益を予測するわけです。)
したがって脳についての理論研究というのはほとんど、我々の解析手法の一覧とほぼ同じ構造をしています。神経にインスパイアされたニューラルネットは当然として、ベイジアンの各手法、そしてなによりdeep learningは脳の理論としてよく登場します。(脳の理論として出てこないのはSVMくらいかな。)
私がやっていた実験的な脳研究とは例えると、マーケティングの解析をやっているブラックボックス(例えばアルベルト)を外から見て、突っついて(すなわち実験的に介入して)内部がどんな解析手法を実行しているか推定するというものだったわけです。今度は中身の方になったわけですが、手法と知識は共通です。
だからより進んだ脳の理解の探求と、より進んだ解析手法の探求も同じようなこととなります。

最後に、知識という点での共通もあります。脳研究と心理学研究からもたらされた考えが、今ではマーケティングの分野で必須になっている例があります。たとえば、人は自分の行動の理由を説明できない、無意識や直感で行動がきまるということ、プライミングが無意識に選択に影響を与えること、我々の行動は速く直感的なシステムと遅く意識的なシステムが拮抗する形で支配されていること、反応時間に無意識のバイアスが表れることなどです。これらの知識によりマーケティングは消費者が言葉で語る建前を超えてその心について多少なりとも知ることができるようになりました。

このように多くの知識、方法の共通点があり、マッチする仕事を見つけたと思っています。みなさんもどうですか?いまALBERTでは積極採用中のようです。詳細はこちらをご覧になってください。

The post 神経科学からマーケティングへ…違いと意外な類似 first appeared on ALBERT Official Blog.

Viewing all 191 articles
Browse latest View live