焼肉が食べたい

ただの日記です。技術的に学んだことも書こうと思っていますが、あくまで自分用メモです。 プロフィールはこちら。https://chie8842.github.io/aboutme/

ETL環境の使い分け

この記事は、AWS Analytics Advent Calendar 2021の12日目の記事です。

AWS上でETLを行う場合の環境の使い分けについて書こうと思います。

ここでは、AWS Glueを利用したデータ管理についてご紹介しようと思います。 AWS Glueは、ETLツールとして認識している人が多いかもしれませんが、データ管理のための様々な仕組みがあります。 そのうちいくつかをご紹介しようと思います。

ETLの構成要素

ETLの構成要素として、ETL実行環境とワークフローエンジンがあります。ETL実行環境とは、その名の通り、ETL処理を行うアプリケーションが実際に動作する環境を指します。一方ワークフローエンジンとは、ETL処理の依存関係を定義して、順番に実行するためのものです。多くはDAG(有向非巡回グラフ)と呼ばれる形式で処理順序が記述され、失敗したときにどこで失敗したか確認したり、リトライを簡単にすることができます。本稿では、AWSで利用できるETL実行環境とワークフローエンジンを紹介します。

ETL実行環境

AWS Lambda

サーバレスのアプリケーション実行環境として、最も多くのエンジニアに馴染みが深いといってもいいのがAWS Lambdaではないでしょうか。ETL実行環境としてみたときのLambdaのメリットとして、好きなプログラミング言語やライブラリといったランタイム環境を利用できるということもあります。アプリケーション作成という意味では当たり前のように感じるかもしれませんが、ETLは、特に大規模データを処理する場合にはPythonJavaで作成された決まったフレームワークに依存した環境を用意することもあります。 しかしデータエンジニアではなく、アプリケーションやインフラエンジニアがデータパイプラインを作成する場合に、Golangなどの普段利用しているランタイム環境のほうが都合の良い場合もあります。一方で、1つの実行環境利用できるCPUやメモリといったリソースに制限があります。また、実行時間制限も存在します。1回に処理するデータ量が10GB以下の場合で、好きなランタイムを利用してETL処理を行いたい場合におすすめの環境になります。

ECS/EKS

すでにアプリケーションの実行環境としてECSやEKSといったコンテナオーケストレーション環境が導入されている場合、その環境と別にLambdaを利用するのでなく、利用中のECS/EKS上でETL用のコンテナを起動するということも考えられます。Lambdaと比べると環境構築や管理の手間がかかるため、もともと利用していない場合はおすすめしませんが、すでに利用している環境がある場合は、あいのりすることで管理が楽になります。また、Lambdaと異なり、リソースの最大容量の制限や実行時間制限もないため、データ量が数十GB以下であり、Lambdaではリソースや実行時間の制限に不安がある場合も、ECSやEKSを利用することで解決します。

AWS Glue

AWS GlueはETLを行うためのサービスです。TB以上の大規模なデータ処理や、複雑なデータ処理もサポートするための機能が揃っています。AWS GlueのETL環境には、Python ShellとApache Sparkという分散処理フレームワークを利用する環境の2種類があります。 1台のサーバでは処理しきれない大量データに対するETLを行う場合は、GlueのApache Spark環境を利用します。Apache Sparkは、大きなデータをあたかも1台のサーバで処理するかのようにETL処理を記述して、実際には複数のサーバ上で分散処理を行い、その際の障害時のリトライや複数サーバ上のタスクのスケジューリング、データ転送といった複雑さを管理してくれるソフトウェアです。また、さまざまなデータソースに接続できるコネクタや、データをカタログ化して利用しやすくする機能もあります。数十GB以上のデータを一度に処理する場合や、複雑なETL処理を一元的に管理したい場合は、AWS GlueのApache Spark環境を利用するのがいいと思います。 また、GlueのPython Shellは、AWS Lambdaよりも大きなリソースをもつコンテナを起動して、Pythonの処理を実行することができます。Lambdaではリソースや実行時間の制限に不安があるけれども、既存のECSやEKSがなく、管理の手間を増やしたくない場合は、Glue Python Shellを利用するのがおすすめです。

AWS Glue DataBrew

AWS Glue DataBrewは、ノンコードで大量データに対するETL処理を記述することのできるサービスです。また、品質チェックやPII Detection/Maskingの機能も存在します。BIや機械学習の前処理として、データアナリストやデータサイエンティストが利用するのにも適しています。特殊で複雑な処理が必要な場合は、Glueなどを利用してコードで表現する必要が出てくる場面があるかもしれませんが、プログラミングに慣れていない人でも管理できる環境として重宝できます。Excelのような感覚でノンコードで利用できるにもかかわらず大量データを全量データを処理できるのがポイントです。

ワークフローエンジン

Step Functions

Step Functionsは、APIアクションの依存関係を定義して、順に実行できます。数千の処理を並列で処理することも可能で、安価に大規模に利用することができます。

Amazon Managed Workflows for Apache Airflow(MWAA)

MWAAは、Apache Airflowというオープンソースのワークフローエンジンのマネージドサービスです。ワークフロー管理をPythonプログラムで記述するので、ダイナミックにDAGを生成できるといった特徴があります。また、各タスクはコンテナ上で実行するので、小さな処理であればETL実行環境としても利用することができます。AWS以外のETL実行環境とも接続するような場合も、OSSとして開発されたAPIを利用して簡単に実現することができます。

Glue Workflow

Glue Workflowは、上で説明したAWS Glueの機能の一つとして提供しているワークフローです。トリガー、ジョブ、クローラの3種類のコンポーネントを組み合わせることで、ワークフローを組み立てます。ETL処理の依存関係が医療する実行環境がGlueのみに閉じている場合は、1つのサービスで全てを実行できるので適しています。

まとめ

AWSにおけるETL環境の使い分けについて記述しました。 ETLはデータ活用をはじめるための重要な第一歩になります。また、適切なサービス利用により、管理を楽にすることができます。 ぜひ使ってみてください。

データ分析に関して今年読んだ本

この記事は、datatech-jp Advent Calendar 2021の21日目の記事です。 (書くの遅くなってごめんなさい!)

datatech-jp の紹介

今年の夏、さまざまな縁から、datatech-jp というコミュニティを立ち上げました。 自分自身は、The Self-Service Data Roadmap という本の読書会を主催しましたが、 他にも有志によってAirflow相談会、dbt勉強会などのイベントが行われたり、「Data Management at Scale」と 「実践データ基盤への処方箋」の読み会が企画されております。

自分としては、データエンジニアからデータ活用に関わるビジネスサイドの人など、さまざまな人の知見が集まるコミュニティとして成り立ったらいいな、と思っています。

もし興味ある方いらっしゃいましたら、是非URLより参加お願いします。

今年読んだ本

さて、このブログでは、今年1 読んだデータ分析関連の本について厳選4冊でご紹介したいと思います。 自分は今までソフトウェアエンジニアとして、技術書を読むことが圧倒的に多かったですが、今年は視野を広げたいという気持ちから、意識的にデータをどう活用するかなど、ビジネス寄りの本を読むことを心がけました。なので、読んだ本もビジネス寄りの本を含みます。

1. The Self-Service Data Roadmap

www.amazon.co.jp

@tall_tree_desu に紹介されて、読み会を企画することになった本ですが、 結果的にNetflixUberなどのグローバルの事例を交えて具体的にデータ基盤のあるべき姿がまとめられていて、とても勉強になりました。特定のクラウドサービスやツールの使い方ではなく、それでいて抽象的な内容に閉じずに目指すべき姿と同実現すべきかが具体的に語られていて、好感がもてる本だと思いました。

2. AFTER DIGITAL 2

www.amazon.co.jp

技術とビジネスの中間地点としてちょうどよく、エンジニアもデータ活用を行う経営者や事業責任者にとっても勉強になる本だなと思いました。データを貯めても宝の山にはならない、など、自分としても経験のある場面があって、共感できました。また、最近よく聞くワードとなった、DXとはなにか、を語る本の一つとして参考になりました。

3. 個人情報保護法の基本と実務対策がよ〜くわかる本

www.amazon.co.jp

上記1. の読書会で紹介されていて、興味があったので買って読んだ本です。データ活用が進むにつれて、個人情報をどのように管理するかは重要な課題になってきています。そもそも個人情報とはなにか、守る方法としてどういう方法が考えられるのかを、日本や海外の法律の観点から理解するのに役に立ちました。データマスキングの方法や個人情報の種類(レコード単体が個人情報を含むものからk-anonymity、l-diversityなどの考え方)なども勉強になりました。

4. データ・ドリブン・マーケティング―――最低限知っておくべき15の指標

www.amazon.co.jp

データ活用といえばマーケティング、というところで、データ活用方法の勉強として読みました。企業風土をデータドリブンの意思決定を行うようにするには、という、経営者目線の本として参考になりました。この本には具体的な分析手法についての説明はなかったので、現場の人間としては、マーケティングや分析手法についての本をあわせて読みたいと思いました。ちなみにマーケティング手法については、昨年読んだ以下の本がお気に入りです。

www.amazon.co.jp

さいごに

データ分析の主役はソフトウェアエンジニアリングよりもどうビジネスに活かせるかを考える方が重要になってきているように感じます。自分も技術とビジネスの両面からデータ分析の発展に関われるように頑張りたいと思います。


  1. 以前に読んで読み返した本も含みます

去年の振り返りと今年がんばること

こういうの書いたことなかったけど気が向いたので書いてみました!とはいえ昨日書き終わらなくて年明けてしまった!

去年の振り返り

去年の振り返りをかきます!

転職

Googleに転職しました。 スカウトは3,4年前からくることがあったけど受けたことはなくて、ちょうどいいタイミングで興味のあるポジションを紹介してもらったので受けてみてました。 Web企業での開発も楽しくてそういう仕事を続けたい気持ちも残っていたのでオファーもらったあともけっこう悩んだけど、転職しました。 GCPのツールを作ったりPoCをしたりするチームです。 12月入社なのでまだキャッチアップ中の状況ですが、上司も同僚もとても親切だし環境もよくごはんがおいしいので、今のところとても楽しいです。はやく貢献できるようにがんばりたいです。

前職でのしごと

去年は主に既存サービス向けの検索改善や推薦システム構築と、新規事業向けの検索システム構築をやっていました。KPIを考えたり色んな人を巻き込んだりと、主にビジネス面が鍛えられたこと、またElasticSearchやSolrのコードを読んで内部構造を勉強できたので楽しかったです。 あとはブリストルに出張してグローバルチームとの開発もやりました。

Publication

海外登壇2回、国内登壇3回、オーガナイズ3回、ブログ記事は1件行いました。 アウトプットすると人からいろいろなフィードバックや新しい情報を得られるので楽しくやっていました。 転職したので来年は登壇の機会は減りそうだけど、興味のある勉強会には積極的に参加していきたいです。

Kaggle

3月にPetFinderに1週間だけチャレンジして、PrivateLB18位で銀メダル(トップ1%)になりました。ただシェイクがあったので運が良かった部分もあると思います。

競技プログラミング

今までやったことがなかったのですが、流行っているのでAtCoderの問題を解いてみたりしました。転職のためにはじめたわけではなかったですが、そのあとコーディング面接の練習にも使いました。ランクが上の人の解き方を見ると、あー、こういう解き方があるのか、とか、こんなに短く書けるのか、とか感動しました。折を見て次はコンテストで上のランクを目指す挑戦もしてみたいです。

ISUCON

@takegue、@himktと一緒にはじめてでてみたけど大敗しましたorz チーム練習をしてあーだこーだ考えたりして楽しかったです。 ちゃんと準備して出られる機会があったらまたチャレンジしてみたいです。

資格

転職に伴ってGCPのProfessional Data Engineerの資格をとりました。 Hadoopとかビッグデータの知識があれば解ける感じの問題なので、特に勉強しなくてもとれました。でも「資格とって」、と言われた2日後にとったのでびっくりされました。(勢い)

プログラミング言語

Rustとgoを勉強しました。個人的にはRustが楽しいなぁと思いました。 今の仕事ではgoを使う機会のほうが多そうです。

OSS

Publicに公開するようなものは対して作ってなかったです。 Contributionとしては、TensorFlowやgensimにちまっとしたPRを投げたり、TensorFlowのドキュメント翻訳をやっていました。 強いて言えばTensorFlowドキュメント翻訳のCIツールは主開発者として作りました。

github.com

英語

例年どおり、勉強したりしなかったりを繰り返していました。 英語がペラペラの@ayemos におしえてもらったカランメソッドや、TOEIC English Upgrader、BBC 6minute Englishなどのスマホアプリを使ってシャドーイングをしていました。しかしなかなか上達しなくて凹みました。。

しごと以外

仕事以外のイベントもまとめてみます!

引っ越し

2年に一度ほど引っ越しをする習性があるのですが、今回は初めて便利屋の友だちを呼んで軽トラで引っ越すをやってみました。 自分でやるといろいろ大変で、引っ越し屋さんの偉大さがわかりました。笑

スポーツ

2週間に1回くらい、朝7時からスポル大井町で友達と早朝テニスをやっています。これは来年も継続したい。 健康のためにはストレッチや筋トレも毎日やりたいけれど、やったりやらなかったりでした。あとは毎朝なぜか朝起きたら壁で逆立ちする習慣があります。

旅行

去年は海外出張が多かったのもあり、あまり遠くには出かけなかったです。 前職で同僚とスノボやツーリングにいったり、一人で別府温泉にいって積ん読消化していたりしました。

電子工作にチャレンジした

前職でハードウェアエンジニアの席が近くて、興味が湧いて自分も3Dプリンタ買ってCADを使って小物をつくったり、M5Stackで窓の防犯ブザーをつくったりしました。 Mint60の足を作ったら売って欲しいという声があって、boothで売ったら3Dプリンタ代の半分くらいの儲けがありました。

f:id:chie8842:20200101155851j:plainf:id:chie8842:20200101155916j:plain

photos.app.goo.gl

また、前職で同僚たちと一緒にNANDだけで24時間耐久全加算器を作る会をやったのがエモくて楽しかったです。またやりたいなぁ。。
f:id:chie8842:20200101160320j:plain

でけたー😃ゼロから始める24時間耐久電子工作大会終了です。おやすみなさいー pic.twitter.com/Go7be89J4b

— ち (@chie8842) November 17, 2019

投資の勉強をした

いちどちゃんと勉強したほうがいいだろうと思ったけどお金は使う方も貯める方も意識が低く、全然勉強してきませんでした。 老後に対する不安があるので一念発起して証券口座を作って実際に投資をしてみました。 えいっと買った株が2ヶ月放置しただけで1.5倍になってたので才能あるかもしれません!(フラグ)

今年がんばること

今年頑張ることをかきます!

勉強

ここ3年ほどは、推薦、データエンジニア、機械学習、インフラ、検索とわりとその場で求められることをやってきたので、エンジニアとして幅を広げたりビジネス感覚とのバランスがとれるようになってきたできた気がしますが一方で、全部中途半端でよくない気もしています。今の仕事ではデータエンジニアリングを主に担当するので、そのへんの知識をもう一度勉強するのと、それに伴って低レイヤーの勉強をしたいです。 あとビジネススキルも伸ばしたいです。

早寝早起き

前職では朝起きれないキャラだったのですが、転職してから朝ごはん目当てで会社に9:30に着いています。 せっかくなので継続して朝強いキャラになりたいです。

英語

今まで英語でコミュニケーションをとれるようになりたいと思うものの英語の勉強に苦手意識があり、そこまで仕事上必要性が高くなかったこともあって何度も挫折しています。 転職して英語の必要性が格段にあがったので、今年は英語ペラペラになりたい。

体を動かす

わたしは肺が弱くて風邪を引くとすぐ肺炎になったり発作が出たりするので、意識的に健康でいられるように体は動かすようにしています。継続的に運動するぞ!

アンテナを張りつづける

いろんなことにアンテナを張って生存戦略考えて生きていきたいです。エンジニアとしてもそれ以外の面でも。

Elasticsearch7.2でkuromoji_ipadic_neologd_tokenizerのsearchモードとsynonym_token_filterを一緒に使うとエラーが出る

TL;DR

Elasticsearch7.2でKuromoji IPADic Neologd TokenizerのsearchモードとSynonym Token Filterを使うとエラーが出る。
エラーを回避するには、Synonym Token Filterを利用するanalyzerではkuromoji_tokenizerのnormalモードを使う

発生した問題

ElasticsearchでKuromoji IPADic Neologd TokenizerのsearchモードとSynonym Token Filterを一緒に使ったところ、インデックス作成時にエラーが出た。

/var/log/elasticsearch/[cluster name].logのエラー

エラーメッセージ(クリックして表示)

[2019-09-19T05:57:48,919][DEBUG][o.e.a.a.i.t.p.TransportPutIndexTemplateAction] [n01] failed to put template [shops_template]
java.lang.IllegalArgumentException: failed to build synonyms
        at org.elasticsearch.analysis.common.SynonymTokenFilterFactory.buildSynonyms(SynonymTokenFilterFactory.java:138) ~[?:?]
        at org.elasticsearch.analysis.common.SynonymTokenFilterFactory.getChainAwareTokenFilterFactory(SynonymTokenFilterFactory.java:90) ~[?:?]
        at org.elasticsearch.index.analysis.AnalyzerComponents.createComponents(AnalyzerComponents.java:84) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.index.analysis.CustomAnalyzerProvider.create(CustomAnalyzerProvider.java:63) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.index.analysis.CustomAnalyzerProvider.build(CustomAnalyzerProvider.java:50) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.index.analysis.AnalysisRegistry.produceAnalyzer(AnalysisRegistry.java:584) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.index.analysis.AnalysisRegistry.build(AnalysisRegistry.java:534) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.index.analysis.AnalysisRegistry.build(AnalysisRegistry.java:216) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.index.IndexService.<init>(IndexService.java:180) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.index.IndexModule.newIndexService(IndexModule.java:411) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.indices.IndicesService.createIndexService(IndicesService.java:563) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.indices.IndicesService.createIndex(IndicesService.java:512) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService.validateAndAddTemplate(MetaDataIndexTemplateService.java:235) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService.access$300(MetaDataIndexTemplateService.java:65) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService$2.execute(MetaDataIndexTemplateService.java:176) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.ClusterStateUpdateTask.execute(ClusterStateUpdateTask.java:47) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.service.MasterService.executeTasks(MasterService.java:687) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.service.MasterService.calculateTaskOutputs(MasterService.java:310) ~[elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.service.MasterService.runTasks(MasterService.java:210) [elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.service.MasterService$Batcher.run(MasterService.java:142) [elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.service.TaskBatcher.runIfNotProcessed(TaskBatcher.java:150) [elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.cluster.service.TaskBatcher$BatchedTask.run(TaskBatcher.java:188) [elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingRunnable.run(ThreadContext.java:688) [elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:252) [elasticsearch-7.3.2.jar:7.3.2]
        at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:215) [elasticsearch-7.3.2.jar:7.3.2]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
        at java.lang.Thread.run(Thread.java:835) [?:?]
Caused by: java.text.ParseException: Invalid synonym rule at line 10
        at org.apache.lucene.analysis.synonym.SolrSynonymParser.parse(SolrSynonymParser.java:72) ~[lucene-analyzers-common-8.1.0.jar:8.1.0 dbe5ed0b2f17677ca6c904ebae919363f2d36a0a - ishan - 2019-05-09 19:35:41]
        at org.elasticsearch.analysis.common.SynonymTokenFilterFactory.buildSynonyms(SynonymTokenFilterFactory.java:134) ~[?:?]
        ... 27 more
Caused by: java.lang.IllegalArgumentException: term: 焼餃子 analyzed to a token (焼餃子) with position increment != 1 (got: 0)
        at org.apache.lucene.analysis.synonym.SynonymMap$Parser.analyze(SynonymMap.java:325) ~[lucene-analyzers-common-8.1.0.jar:8.1.0 dbe5ed0b2f17677ca6c904ebae919363f2d36a0a - ishan - 2019-05-09 19:35:41]
        at org.elasticsearch.analysis.common.ESSolrSynonymParser.analyze(ESSolrSynonymParser.java:57) ~[?:?]
        at org.apache.lucene.analysis.synonym.SolrSynonymParser.addInternal(SolrSynonymParser.java:114) ~[lucene-analyzers-common-8.1.0.jar:8.1.0 dbe5ed0b2f17677ca6c904ebae919363f2d36a0a - ishan - 2019-05-09 19:35:41]
        at org.apache.lucene.analysis.synonym.SolrSynonymParser.parse(SolrSynonymParser.java:70) ~[lucene-analyzers-common-8.1.0.jar:8.1.0 dbe5ed0b2f17677ca6c904ebae919363f2d36a0a - ishan - 2019-05-09 19:35:41]
        at org.elasticsearch.analysis.common.SynonymTokenFilterFactory.buildSynonyms(SynonymTokenFilterFactory.java:134) ~[?:?]
        ... 27 more
[2019-09-19T05:58:00,832][INFO ][o.e.c.m.MetaDataCreateIndexService] [n01] [shops] creating index, cause [auto(bulk api)], templates [], shards [1]/[1], mappings []
[2019-09-19T05:58:00,983][INFO ][o.e.c.m.MetaDataMappingService] [n01] [shops/2DRfIkXNS66azf7EEvGuZw] create_mapping [_doc]

ちなみにエラーが出たときのAnalyzerとmapの設定はこれ。

  "settings": {
    (省略)
    "analysis": {
      "filter": {
        "my_synonym": {
          "type": "synonym",
          "synonyms_path": "synonym.txt"
        }
      },
      "tokenizer": {
        "kuromoji_search": {
          "type": "kuromoji_ipadic_neologd_tokenizer",
          "mode": "search"
        }
      },
      "analyzer": {
        "synonym_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_search",
          ...
          "filter": ["my_synonym", ...]
        },

原因調査してわかったこと

ログに以下のエラーがあることから、synonym.txtの「焼餃子」を含む行の構文に問題があるらしい。

Caused by: java.lang.IllegalArgumentException: term: 焼餃子 analyzed to a token (焼餃子) with position increment != 1 (got: 0)

ちなみにsynonym.txtの中身はこんなかんじ

...省略...
焼き餃子, 焼きぎょうざ, 焼餃子

ここで、「焼餃子」をsynonym_analyzerでtokenizeした結果を見てみる。

  "settings": {
    (省略)
    "analysis": {
      "tokenizer": {
        "kuromoji_search": {
          "type": "kuromoji_ipadic_neologd_tokenizer",
          "mode": "search"
        }
      },
      "analyzer": {
        "kuromoji_search_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_search",
          
        },

Analyzeした結果

$ curl -XPOST 'http://localhost:9200/hoge_index/_analyze?pretty' -H "Content-type: application/json" -d '{"analyzer": "kuromoji_search_analyzer", "text": "焼餃子"}'
{
  "tokens" : [
    {
      "token" : "焼",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "焼餃子",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0,
      "positionLength" : 2
    },
    {
      "token" : "餃子",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    }
  ]
}

エラーメッセージにあった、position increment != 1 (got: 0)positionっぽいものがある。 Analyzerのtokenizerにkuromoji_ipadic_neologd_tokenizersearchモードを利用すると、synonymのanalyzeの結果として、複合語を考慮した出力がされるが、「焼」と「焼餃子」でpositionの値が一緒であるためにpositionのincrementのエラーが出ているっぽい。 ソースコードを追っていってもその様子はけっこう容易に理解できた。 ただ、positionのcheckはlucene側に実装があったが、なんのためのチェックかはコメントなどもなくわからなかった。

次に過去のIssueを調べた結果、以下のIssueコメントを見つけた。

Ensure TokenFilters only produce single tokens when parsing synonyms by romseygeek · Pull Request #34331 · elastic/elasticsearch · GitHub

synonymを使いたいときは、normalモードを使えとのこと。 そのとおりにしたらうまくいった。

一応試しにnormalモードのAnalyzerを使って「焼餃子」Analyzeしてみる。

Analyzer

    "analysis": {
      "tokenizer": {
        "kuromoji_normal": {
          "type": "kuromoji_ipadic_neologd_tokenizer",
          "mode": "normal"
        }
      },
      "analyzer": {
        "kuromoji_normal_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_normal"
        }
       ...

Analyzeした結果

$ curl -XPOST 'http://localhost:9200/hoge_index/_analyze?pretty' -H "Content-type: application/json" -d '{"analyzer": "kuromoji_normal_analyzer", "text": "焼餃子"}'
{
  "tokens" : [
    {
      "token" : "焼",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "餃子",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    }
  ]
}

normalモードだと複合語である「焼餃子」が消えて同じpositionをとるtokenがなくなっていた。

最終的な構成

normalモードで動くとはいえ、複合語も考慮したインデキシングはしてほしいので、最終的には以下のようにした。

Analyzerの構成

    "analysis": {
      "filter": {
        "my_synonym": {
          "type": "synonym",
          "synonyms_path": "synonym.txt"
        }
      },
      "tokenizer": {
        "kuromoji_normal": {
          "type": "kuromoji_ipadic_neologd_tokenizer",
          "mode": "normal",
          "discard_punctuation": "true",
          "user_dictionary": "userdict.txt"
        },
        "kuromoji_search": {
          "type": "kuromoji_ipadic_neologd_tokenizer",
          "mode": "normal",
          "discard_punctuation": "true",
          "user_dictionary": "userdict.txt"
        }
      },
      "analyzer": {
        "kuromoji_search_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_search",
          "char_filter": ["kuromoji_iteration_mark"],
          "filter": [
            "lowercase",
            "cjk_width",
            "kuromoji_baseform",
            "kuromoji_part_of_speech"
          ]
        }
        "synonym_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_normal"
          "char_filter": ["kuromoji_iteration_mark"],
          "filter": [
            "lowercase",
            "cjk_width",
            "kuromoji_baseform",
            "kuromoji_part_of_speech",
            "my_synonym"
          ]
        },
       ...
      }
    }

mapping

...
    "properties": {
      "hogehoge": {
        "type": "text",
        "fields": {
          "kuromoji_field": {
            "type": "text",
            "analyzer": "kuromoji_search_analyzer"
          },
          "synonym_field": {
            "type": "text",
            "analyzer": "synonym_analyzer"
          },
          ....
        }
      },
...

query

curl -XGET 'http://localhost:9200/hoge_index/_search?pretty' -H 'Content-Type: application/json' -d'{
  "query": {
    "multi_match" : {
      "type" : "cross_fields",
      "query" : "焼餃子",
      "fields" : ["hogehoge.kuromoji_field^5", "hogehoge.synonym_field"],
      "operator" : "and"
    }
  }
}'

その他試したこと1

www.elastic.co

上記を見ると、The tokenizer parameter controls the tokenizers that will be used to tokenize the synonymとあるので、以下のようにsynonym filterのパラメータにtokenizerを渡せばsynonymのTokenizerだけnormalモードを使ってその他の単語のTokenizeはsearchモードを使うことができるのかと思ったけど、最初と同様のエラーがでてできなかった。

    "analysis": {
      "filter": {
        "ja_synonym": {
          "type": "synonym",
          "synonyms_path": "synonym.txt",
          "tokenizer": "kuromoji_normal"
        }
      },
      "tokenizer": {
        "kuromoji_normal": {
          "type": "kuromoji_ipadic_neologd_tokenizer",
          "mode": "normal"
        },
        "kuromoji_search": {
          "type": "kuromoji_ipadic_neologd_tokenizer",
          "mode": "search"
        }
      },
      "analyzer": {
        "kuromoji_search_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_normal",
          "filter": ["ja_synonym"]
        }

その他試したこと2

ちなみに、このブログを見ると、

Synonym Token Filter を日本語と一緒に使用する場合は、辞書の内容もトークナイザーの仕様にあわせて単語を分割して登録しておく必要があります。

とあるが、このやり方だとインデックス作成時はエラーが出ないが、一つの単語として認識してくれないのでシノニムとしては使えなかった。 Elasticsearch5.3あたりのドキュメントを見ると、The tokenizer parameter controls the tokenizers that will be used to tokenize the synonym, and defaults to the whitespace tokenizer. とあるので、こちらのバージョンでの話なのかもしれない。

Web+DB Press Vo.104の特集1を執筆しました!

Web+DB Press Vo.104の特集1を執筆しました。わたしにとっては人生初の執筆で、学ぶことも多かったので、せっかくだからブログに書いてみます。

gihyo.jp

構成

章構成は共著者で話して決めました。 1つの特集で初めてさんでもPythonのインストールから機械学習モデルをつくってアプリケーション化するところまでできる構成になっています。

タイトル:イマドキPython入門
第1章:Pythonはどんな言語?
広く使われる理由を歴史とともに掘り下げる……@puhitaku
第2章:開発環境を整えよう
はまらない導入手順と開発ツールの使い方……@puhitaku
第3章:文法を押さえよう
基本的な書き方とPython特有の機能……@chie8842,@rhoboro
第4章:科学技術計算と機械学習をやってみよう
NumPy,SciPy,pandas,scikit-learn……@chie8842
第5章:Webアプリケーションを作ろう
Bottleによるアワビの年齢推定アプリの開発……@rhoboro

わたしはこのうちの、3章(共著)と4章の2つを担当させていただきました。 1つの特集でこれだけの内容を盛り込めたのは結構頑張ったのではないかと思います!

執筆経緯と執筆手順

きっかけは、PyCon JPの登壇でした。登壇資料を見た執筆関連者を通じて、一緒に取材を受けた共著の @puhitaku さんから声をかけていただきました。

執筆はすべて、Issue管理や校正含め、作業はほとんどGitHub上でを用いて行いました。markdownで記述でき、執筆ルールも編集側でわかりやすくまとめてくださっていたので、 作業はとてもやりやすかったです。 編集者さんといえばアナログなイメージを持っていたので、担当してくださった@inaoさんが、エンジニアでないのにGitHubを使いこなしていてびっくりしました。

執筆手順は以下でした。

  1. アウトラインを決める
  2. 章ごとにブランチを切ってそれぞれ執筆
  3. 相互レビュー
  4. 編集者の方と一緒に校正
  5. 外部レビュワーによるレビュー

(3~5は何回か繰り返した)

最後の方になると、PDFの見本が出来上がってきて、DropBox上でレビューを行いました。初めてDropBoxのPDF書き込み機能を使いましたが、大人数のレビューもやりやすかったです。 また、個人的に校正ツールとして、RedPenを使いました。

ためになったこと

Pythonについてより深く学ぶことができた

記事を執筆するにあたり、各ライブラリの公式ドキュメントやソースコードを改めて読み返しました。最新の機能や内部的挙動など、わかったつもりだったけれど執筆を通して改めて気づいた点も多々ありました。

また、共著の二人はそれぞれ少しずつ違ったバックグラウンドを持っていたので、相互レビューを通して学んだ点も多くありました。

共著の大変さを知った

執筆前は、共著だと単純に書く量が減るからその分楽だと思っていましたが、全然そうじゃなかったです。笑 執筆速度や、どの時点でどのような品質を目指すか、というところの目安が人によって違います。書き方のクセも違います。なので、各々が少しずつ人に合わせて書く必要がありました。

また、活動場所や活動時間が違いました。私は個人活動としてやっていたから、基本平日は夜遅くしか対応できなかったですが、平日の昼に書くメンバもいました。また、全員別の会社の所属なので、例えば相互レビューをしているときに、気軽に「ここどういう意味?」とか聞くようなことができないという難しさがありました。

こうしたことから、相互レビューは大変で、時間も神経も執筆の何十倍も使いました。

進捗に関して@inaoさんが適切なタイミングでプッシュしてくれましたし、共著の二人とも非常に文章力技術力ともに高かったので、本当に助けられました。

外部レビュワーという存在

今回外部レビュワーとして、@takanoryさんと@terapyonさん、@yutailang0119 さんがレビューに加わっていただき、相互レビューで気づかないいろんな観点での指摘をもらうことができました。 執筆にあたり、「外部レビュワーにレビューしてもらう」ということを知らなかったので、実は様々な技術書がこうした方々に支えられているんだと知りました。

うれしかったこと

Amazonの著者に自分の名前が!

なんだか大物になった気持ちになりました。笑

WEB+DB PRESS Vol.104

WEB+DB PRESS Vol.104

  • 作者: 末田卓巳,林田千瑛,陶山嶺,八谷賢,辰己佳祐,竹澤俊季,服部智,藤岡裕吾,牧大輔,西郡卓矢,松木雅幸,穴井宏幸,新日出海,桑原仁雄,小田知央,ひげぽん,池田拓司,はまちや2,竹原,大場光一郎,大場寧子,松館大輝,日高尚美,Vu Xuan Dung,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/04/24
  • メディア: 単行本
  • この商品を含むブログを見る

自分の落書きがすごくかわいいイラストになった

イラストのデザインとか、キャッチコピーも自分たちで考えたのですが、 イラストは私の落書きをコンセプトとして採用してもらい、落書きから想像できないほどすごくかわいいイラストに変身していて、感動しました。

おわりに

執筆したWeb+DB Vol.104は私のもとにも献本いただけたので、他の章も読んでみましたが、他にも興味深い内容が多かったです。特集2のiPhoneアプリ開発など、ちょうどモバイルアプリも勉強したかったので、楽しく読めました。 まだ買っていない皆様、ぜひ買って読んでください!

時間のかかるデータ処理や機械学習処理が終わったら通知してくれるツールをつくった!

Pythonのメソッドにデコレータをつけるだけで、その処理が終わったらSlackやメールや画面のポップアップで通知してくれるツールを作りました。

github.com

正直そんなに大したツールではないんだけど、 こういう時間のかかる試行錯誤をサポートしてくれるツールを便利だと思ってくれる人が他にもいたらうれしいな、と思うのでブログに書いてみます!

作った背景とコンセプト

わたしは普段、機械学習や、大量データに対するデータ処理や分析をやっています。 いつも時間がかかるスクリプトを回しながら他の仕事をして、定期的にスクリプトが終わったか確認するということをしていたのですが、 これが面倒なので、処理が終わったら通知してくれると便利だなと思ったのが作るきっかけです。

ちなみに、kerasやtensorflow、chainerなどを使う場合だと、以下のツールがあります。

Hyperdash | Machine Learning Monitoring

Hyperdashは、フレームワークからメタデータを取得してスマ―トフォンで機械学習の詳細な進捗具合を見ることができるなど多機能です。 これはすごく便利なのですが、限られディープラーニングフレームワークでしか使えません。 また、利用するフレームワークによって実装方法が異なり使い方が少し複雑です。

わたしはディープラーニング以外に、PySparkを使った分析や、SQLAlchemyを使ってRedShiftに接続してPythonからSQLを実行するということをやることも多いです。 なので、いろいろな場面で使いやすいものがほしいと思い、

  • 汎用的に使えてかつ使い方が簡単
  • 終わったら通知するだけのシンプルな仕様

をコンセプトとして作りました。

使い方

使い方はめっちゃ簡単で、pipでインストールして、configファイルに数行の設定を書いて、処理が終わったら通知してほしいメソッドの上にデコレータをかくだけです。

インストール

pip install easy_notifier

デコレータの記述

@easy_notifier(~/.easy_notifier.cfg)
def test_method()
    ・・・
     処理の中身
    ・・・

test_method()

通知の結果はこんなかんじです。

Slackでの通知

メールでの通知

macのポップアップでの通知

通知の中のreturnはreturn valueで、返り値を表示します。 今見るとわかりにくいのであとで修正しておこう。。。

設定ファイルの中身はこういう感じです。 必要なところだけ埋めて使います。

[easy_notifier]
env = ec2
process_name = test_process
notify_slack = true
notify_gmail = true
notify_mac = false
incoming_webhook_url = 'https://slack/testurl'
slack_id = my_slack_id
channel = my_slack_channel
from_address = test@gmail.com
from_password = password
to_address = test2@xxx.com

以下は各パラメータの説明です。

パラメータ 説明
env 上の通知のinstance_nameの取得方法で、ec2、local、gceのいずれかを指定します。EC2の場合はNameタグをinstance_nameとして利用します。localの場合はhostnameがinatance_nameとなります。gceはまだ実装していなくて、hostnameがinstance_nameとなります。
process_name 上の通知のprocess_nameの表示内容を指定します。何も指定しない場合は、デコレータをセットした対象のメソッド名が利用されます。
notify_[slack|mac|gmail] それぞれ、slack、macのポップアップ、gmailからのメール通知を使うかどうかを設定します。trueもしくはyesの場合、その通知方法での通知が行われます。macのポップアップでの通知をLinuxWindows上で指定した場合は無視されます。
incoming_webhook_url slackでの通知を行う場合は、slack上で通知を受け取るためにincoming_webhookの設定を行い、そのURLをこのパラメータに設定する必要があります。
slack_id ここに、slackのDisplay nameを設定すると、その人にメンションされます。
channel slackで通知してほしいチャンネルを設定します。
from_[address|password] gmailからのメール通知を行う際の通知元のgmailアドレスとパスワードを設定します。
to_address 通知先の任意のメールアドレスを指定します。

あとTODOとして、jupyter notebookのマジックコマンドでも同じことできるようなの作ったら便利かなと思っています。 以上です。 もし使ってやってもいいよという人がいたら、感想とか教えてもらえたらとてもうれしいです!

p3インスタンス(V100)上でCUDA+CUDNN+Tensorflowを動かすのが大変だったのできろく。

p3で機械学習基盤を作ったのだけれど、いろいろややこしかったのでメモしておく。
ただしこれは2017/11/27現在の状況であって、またそのうち移り変わると思う。

環境

OS: Ubuntu

NVIDIA-DRIVERインストール

普通はこれで入る。

sudo apt-get install nvidia-384

でも、確認すると、これでインストールされるのは、nvidia-384.90
nvidiaのページを見ると、nvidia-384.90はv100をサポートしてない。

NVIDIA DRIVERS Linux x64 (AMD64/EM64T) Display Driver

それで、ちゃんとNVIDIAのホームページからvoltaに対応しているnvidia-384.81をインストールすればいいと思った。

でも実はこれじゃだめだった。
理由はあとで説明する。

CUDAインストール

volta自体は、cuda Toolkit version8.0以前を使って構築されたアプリケーションも、
条件付きで動かすことはできるらしい。

Volta Compatibility Guide :: CUDA Toolkit Documentation

が、面倒くさそう。
あと、cudnn7はcuda8.0だとうまく動かない場合があるらしい。

cuda9にする。
インストールの形式は、
Linux -> x86_64 -> Ubuntu -> 16.04 -> runfile(local)
を選ぶ。
ここでdeb(local)やdeb(network)でインストールをすると、
nvidia-driverのバージョンが384.90にアップデートされてしまう。
nvidia-driverのインストールのところでの「これじゃだめだった。」の理由はこれ。
nvidia-driver単体のインストールは行わず、runfileでインストールすると、
nvidia-driver384.81とcuda9.0のコンビでインストールしてくれる。
f:id:chie8842:20171127191626p:plain

ちなみにcuda8だとこれをうまくやってくれるインストール形式がない。

結局のところのnvidia-driverとcudaのインストール手順は以下。

sudo apt-get update
wget https://developer.nvidia.com/compute/cuda/9.0/Prod/local_installers/cuda_9.0.176_384.81_linux-run
sudo apt-get install -y gcc && sudo apt-get install -y make
sudo sh cuda_9.0.176_384.81_linux-run

nvidia-smiでGPUの動作状況を確認する。

$ nvidia-smi

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.81                 Driver Version: 384.81                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla V100-SXM2...  Off  | 00000000:00:1E.0 Off |                    0 |
| N/A   35C    P0    35W / 300W |      0MiB / 16152MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

ついでにPersistence ModeをONにしておく。

$ sudo nvidia-smi -pm 1
Enabled persistence mode for GPU 00000000:00:1E.0.
All done.
$ nvidia-smi
Mon Nov 27 13:19:38 2017
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.81                 Driver Version: 384.81                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla V100-SXM2...  On   | 00000000:00:1E.0 Off |                    0 |
| N/A   37C    P0    21W / 300W |     10MiB / 16152MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

cudnnインストール

インストールパッケージ一覧を見ると、cuda9の場合、cudnnのバージョンは7.0.3しかでてこなかったので、cudnn7.0.3をインストールする。
f:id:chie8842:20171127193028p:plain

cudnnのインストールは、tgzファイルをサーバに配置して、以下を実行すればいい。

mkdir -p /usr/local/cuda/lib64
mkdir -p /usr/local/cuda/include
tar xzvf cudnn-9.0-linux-x64-v7.tgz
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64/
sudo cp cuda/include/cudnn* /usr/local/cuda/include/
sudo ln -sfv /usr/local/cuda/lib64/libcudnn.so.7.0.3 /usr/local/cuda/lib64/libcudnn.so.7

tensorflowインストール

ここまでやって、普通にtensorflowのexampleを動かしてみたけど、
エラーが出る。

apt-get install python3-pip
pip3 install tensorflow-gpu
python3 $HOME/tensorflow/tensorflow/examples/tutorials/mnist/mnist_deep.py
# ImportError: libcublas.so.8.0: cannot open shared object file: No such file or directory

この辺のIssueを見ると、ソースコードをr1.4のソースコードをビルドしないと動かないっぽい。

Upgrade to CuDNN 7 and CUDA 9 · Issue #12052 · tensorflow/tensorflow · GitHub CUDA 9RC + cuDNN7 · Issue #12474 · tensorflow/tensorflow · GitHub

Tensorflowのドキュメントを参考に、ソースコードからビルドする。

すでにtensorflow-gpuをインストールしている場合は、アンインストールする。

sudo pip3 uninstall tensorflow-gpu tensorflow-tenworboard

依存パッケージをいろいろインストール

sudo apt-get -y install python-numpy python-dev python-pip python-wheel
sudo apt-get -y install python3-numpy python3-dev python3-pip python3-wheel
sudo apt-get -y install libcupti-dev

bazel(ビルドツール)インストール

sudo apt-get -y install openjdk-8-jdk
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update && sudo apt-get install oracle-java8-installer
echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
sudo apt-get update && sudo apt-get install bazel
sudo apt-get upgrade bazel

cuda9+cudnn7対応が行われているv1.4.0のタグを指定してtensorflowをgit clone

git clone -b v1.4.0 https://github.com/tensorflow/tensorflow
cd tensorflow

ビルドのオプション設定を行う。
cuda以外のオプションはデフォルトにした。

$ ./configure
You have bazel 0.7.0 installed.
Please specify the location of python. [Default is /usr/bin/python]: /usr/bin/python3.5


Found possible Python library paths:
  /usr/local/lib/python3.5/dist-packages
  /usr/lib/python3/dist-packages
Please input the desired Python library path to use.  Default is [/usr/local/lib/python3.5/dist-packages]

Do you wish to build TensorFlow with jemalloc as malloc support? [Y/n]: 
jemalloc as malloc support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: 
Google Cloud Platform support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Hadoop File System support? [Y/n]: 
Hadoop File System support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: 
Amazon S3 File System support will be enabled for TensorFlow.

Do you wish to build TensorFlow with XLA JIT support? [y/N]: 
XLA JIT support will be enabled for TensorFlow.

Do you wish to build TensorFlow with GDR support? [y/N]: 
No GDR support will be enabled for TensorFlow.

Do you wish to build TensorFlow with VERBS support? [y/N]: 
VERBS support will be enabled for TensorFlow.

Do you wish to build TensorFlow with OpenCL SYCL support? [y/N]: 
No OpenCL SYCL support will be enabled for TensorFlow.

Do you wish to build TensorFlow with CUDA support? [y/N]: y
CUDA support will be enabled for TensorFlow.

Please specify the CUDA SDK version you want to use, e.g. 7.0. [Leave empty to default to CUDA 8.0]: 7.0.3


Please specify the location where CUDA 7.0.3 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:


Invalid path to CUDA 7.0.3 toolkit. /usr/local/cuda/lib64/libcudart.so.7.0.3 cannot be found
Please specify the CUDA SDK version you want to use, e.g. 7.0. [Leave empty to default to CUDA 8.0]: 9.0


Please specify the location where CUDA 9.0 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:


Please specify the cuDNN version you want to use. [Leave empty to default to cuDNN 6.0]: 7.0.3


Please specify the location where cuDNN 7.0.3 library is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:


Please specify a list of comma-separated Cuda compute capabilities you want to build with.
You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus.
Please note that each additional compute capability significantly increases your build time and binary size. [Default is: 7.0]7.0


Do you want to use clang as CUDA compiler? [y/N]: 
nvcc will be used as CUDA compiler.

Please specify which gcc should be used by nvcc as the host compiler. [Default is /usr/bin/gcc]:


Do you wish to build TensorFlow with MPI support? [y/N]: 
No MPI support will be enabled for TensorFlow.

Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]: 


Add "--config=mkl" to your bazel command to build with MKL support.
Please note that MKL on MacOS or windows is still not supported.
If you would like to use a local MKL instead of downloading, please set the environment variable "TF_MKL_ROOT" every time before build.
Configuration finished

ビルドを行う前に、共有ライブラリパスにcudaのディレクトリを追加する。
再起動しても設定を保持してほしいので、/etc/ld.so.confに書き込む。

echo "/usr/local/cuda/lib64" >> /etc/ld.so.conf
sudo ldconfig

ビルドの実行

bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

上記実行すると、/tmp/tensorflow_pkg配下にwhlファイルができている。
これをインストールする。

sudo pip3 install /tmp/tensorflow_pkg/tensorflow-1.4.0-cp35-cp35m-linux_x86_64.whl

ソースコードビルドするのが面倒な人向けに、cuda9+cudnn7.0.3向けにビルドしたバイナリを以下においてみた。

github.com

あらためて、Tensorflowのexampleを実行してみる。

python3 $HOME/tensorflow/tensorflow/examples/tutorials/mnist/mnist_deep.py
...
2017-11-27 12:54:46.049508: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:900] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2017-11-27 12:54:46.049967: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1064] Found device 0 with properties:
name: Tesla V100-SXM2-16GB major: 7 minor: 0 memoryClockRate(GHz): 1.53
pciBusID: 0000:00:1e.0
totalMemory: 15.77GiB freeMemory: 15.36GiB
2017-11-27 12:54:46.049991: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1154] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:1e.0, compute capability: 7.0)
step 0, training accuracy 0.1
step 100, training accuracy 0.82
step 200, training accuracy 0.9
step 300, training accuracy 0.88
step 400, training accuracy 0.9
step 500, training accuracy 0.96
...

ちゃんとGPUを使って動いた。