mitolab's diary

東南アジアで頑張って生きてる人のブログ

『畳み込みニューラルネットワークによるテキスト分類を TensorFlow で実装する · けんごのお屋敷』を理解するための前知識

ちょっと機械学習してみよう、って思って勉強してたら自分がいまどこに居るのかわかりかねてきたので(汗)、頭の整理のためにこれまでの学習の軌跡をまとめてみます。実際には掲題の記事を理解するためのリンク集みたくなりましたので予めご了承ください。

目標

自然言語における5W1H(誰が、いつ、どこで、何を、なぜ、どのように)を、機械学習を用いて分類する。

上記はmecab-pythonだけで出来るんや...(しかもオフラインで!スゲェ!)ということで、、マヌケながら実際はこの前段(or後段)で文章のカテゴリ分類をする必要がありそうなので、その部分で機械学習を取り入れることを目標とします。

動機

とあるアプリにそういう機能をつけたく。

筆者の数学的知識

数学は高校2年まで。偏微分や行列などは独学で学び、わからなければ都度調べる形。

機械学習って?

機械学習(きかいがくしゅう、英: machine learning)とは、人工知能における研究課題の一つで、人間が自然に行っている学習能力と同様の機能をコンピュータで実現しようとする技術・手法のことである。

機械学習の目的は、訓練データから学んだ「既知」の特徴に基づく予測である。

via 機械学習 - Wikipedia

目標達成のためのマイルストーン

TensorFlowを使えばなんとかなるんじゃね?という安易な考えからスタート。「TensorFlow 自然言語処理」でググってよさげだなと思ったサイトが以下。まずはこの記事の理解のために学習する方針とした。

畳み込みニューラルネットワークによるテキスト分類を TensorFlow で実装する · けんごのお屋敷

道筋

上記記事中に、対象とする読者としてこう書いてあった:

ので、10年も前になぜか購入していた以下の本を読んでニューラルネットワークについてまずは復習。

学習とニューラルネットワーク (電子情報通信工学シリーズ)

中古価格
¥1,543から
(2016/9/4 13:24時点)

基本的なニューラルネットワークの考え方、勾配法、誤差逆伝播法(バックプロパゲーション法)、シグモイド関数などの理解に役立った。7章の途中くらいからボルツマンマシンの話になり、めんどくさそうだなと思って読んでない。それでも、この本を読んでから上記WEB記事を見ると理解度は前よりは上がった。それでもわからない単語が出てきたので都度調べた(以下)。

畳み込みニューラルネットワーク(CNN)

自然言語処理における畳み込みニューラルネットワークを理解する · けんごのお屋敷

画像認識における例から、それを自然言語処理(NLP)にどう適用するか、の説明がなされていてイメージしやすかった。

word2vec

これについてはなんとなくイメージはつかめる程度。以下で理解しようと試み中。

Word2Vec のニューラルネットワーク学習過程を理解する · けんごのお屋敷

Vector Representations of Words

enakai00.hatenablog.com

qiita.com

qiita.com

MNIST For ML Beginners

neuralnet.hatenablog.jp

MNIST For ML Beginnersで実行していることは何なのか、softmaxはシグモイド関数の多変量版だとかのくだりが非常に理解しやすかった。また、関連する交差エントロピーについても以下の記事で理解が進んだ。

neuralnet.hatenablog.jp

過学習

ここがよさ気だけどまだ読んでない。

tjo.hatenablog.com

活性化関数

活性化関数 - Wikipedia

ということで

今後も理解を深めつついい加減コードを書いていけるようにしないと。

Hugo、github Pages、wovn.io、ムームードメインを使って楽に短時間でプロフィールページを作る!

最近、初対面の方にお会いすることが多くなってきたので、先日webサービスとアプリを使ってオシャレな名刺を作ってみました*1

で、この際プロフィールページフリーランス時代のものだったので、現状に即した内容にアップデートをしてみました。

できたもの

f:id:mitolab:20160812131646p:plain mitolab

  • 1枚だけのプロフィールページ
  • PC/スマフォ両対応
  • google analyticsでトラッキング可能
  • メールフォーム利用可能
  • ブログへの拡張性もある
  • 日本語/英語両対応

短時間でこれだけのものが、ドメイン代だけでまかなえます。

プロフィールページ作成に使うもの

  1. Hugo... 静的サイト生成ツール
  2. Github Pages... 静的サイトを公開できるgithubのサービス
  3. ドメイン... ムームードメインで取得
  4. wovn.io... htmlに一行挿入するだけ簡単ローカライズサービス

作成手順

基本的な手順は、

Hugo + GitHub Pagesでブログを作る

の記事を参照しつつ、ドメイン設定に関しては、

GitHub Pagesで静的なサイトを公開し、独自ドメインを設定する

こちらの記事を参照しながら進めました。

最後に、wovn.ioを使って英語と日本語を切り替えられるようにしました。

Hugoテンプレート適用

Hugoのいいところは、多数のフリーテンプレートを用意していること。しかも結構シンプルでオシャレなものが多い印象です。

f:id:mitolab:20160812133009p:plain http://themes.gohugo.io/

多分、テンプレを探すのに一番時間を費やしました...。最終的に決めたものがこちら。

f:id:mitolab:20160812133119p:plain Hugo Theme: Strata

1枚で完結して、且つスマフォ/PC両対応だったのでこれにしました。あとこれは別に選定基準ではなかったんですが、google analyticsのトラッキングコードを設定出来るようになっていたり、メールフォームもすぐ使えるようにしていたりで、かゆいところに手が届くテンプレで素晴らしいです。背景画像くらいは変えたほうがいいかもしれないけどそのまんま使ってます...。

あと、左下のアイコンを出す出さないとか、右カラムの画像類を出す出さないとかは全てconfig.tomlで設定できて便利です。

注意点として、今回は1枚だけのページを作りたかったので、上記参照した手順記事記事の枠を作ってみるから記事を書いてみるまでは飛ばして、テンプレに付属のexampleSiteに入っている、config.tomlhugo new site <site-name>した際のトップディレクトリに配置(デフォのやつを上書き)して、その中身をいじってあげればOKです。

あと、テンプレに付属のメールフォームは、formspree.ioというプロキシサービスを使っていて、使う場合はサイトをgithubにpushして、ドメインも適用してから、実際にフォームから自分宛にメールを送信して、来たメールでconfirmするだけでフォームが利用可能になります。月に1000通までは無料らしいので余裕で足りると思います。

Github Pages

基本的には、

  • githubリポジトリを作る
  • gh-pagesというブランチを作る
  • 上記ブランチにpushする

という作業だけで、http://[ユーザ名].github.io/[リポジトリ名]というurlにページを公開できます。それか、[ユーザ名].github.ioというリポジトリを作ることでも同様のことが出来るようで、2通りのやり方があるみたいです。今回は前者のやり方でやってみました。

ドメイン設定

ムームードメインでの作業と、Github Pagesでの作業にわかれます。

ムームードメインでは既にドメインを取得済だったので、DNSのAレコードを変更/追加してあげました。加えて、tumblrでCNAMEレコードを使っていたんですが不要なので消しました。

GithubPagesでは、リポジトリのSettingsからCustom Domainを設定してあげると、自動的にリポジトリにCNAMEファイルができます。それで、qiita記事のこちらの手順と同等の手順となります。

f:id:mitolab:20160812134456p:plain

ローカライズ

wovn.ioを使うと簡単にローカライズできました。画面もシンプルなのでいじってみれば使い方は理解できると思います。手順も公式で用意されています。

ただ1つわかりにくかったのが、htmlに挿入する1文が見つけにくいこと。上記手順では、ダッシュボードがブランクの際のページに1文が書いてあるのですが、一度ページを登録してしまうと、その1文がどこかに消えていなくなってしまい、色々ボタンを探してみないとわからないという状態になってしまいました。

最終的には、右上のドロップダウンにフォーカスして、アカウント > コードスニペット を選択すると1文が表示されます。

<script src="//j.wovn.io/1" data-wovnio="key=xxxxx" async></script>

こういうやつです。

まとめ

以上です。簡単に多機能なページが作れてしまうのでオススメです。今回は静的ページ生成サービス探しやテンプレ探しに時間がかかりましたが、既にテンプレも決まっていてドメインも取れている状態であれば、1時間では終わりそうなボリュームかと思います。

では、何かの参考になれば幸いです。

aws serverlessでfacebook messenger botを試してみた

前回のポストから時間がだいぶ空いてしまった...反省。やったことと言えば件名にあることくらいです。まだ中途半端ですが忘れてしまうのでとりあえずメモします。

作ろうと思っているもの

今学んでいるBLOF理論や植物生理、微生物、土の性質、etc...農作物の生産に関するQ&A botができれば便利かなぁと思って着手し始めました。

想定する使い方はいたってシンプルで、

  1. 質問をメッセンジャーに音声で質問する(農作業中テキストを打つとかめんどくさくてしないので)
  2. botがその答えを返してくれる

というもの。


ゆくゆくは個別の圃場情報を予めinputしておいて、例えば「A圃場に必要な肥料は?」とか聞くと、「はい、次の施肥をしてください:① バーク堆肥を250kg、アミノ酸肥料を10kg、鉄肥料を2kg、マンガン肥料を1kg を混ぜて施肥してください ② 酵母菌を30g、砂糖を400g、水を5Lを混ぜて施肥してください、③ 1,2完了後、透明マルチを被せて3日間養生してください」とかそういう答えが返ってくるようなものができれば便利だなぁと思ったりします。つまりは圃場メンテナンスにかけるルーチンプロセスを少しでも省略化することができれば便利だなぁと。


利用サービス

作り方

qiita.com

developers.facebook.com

http://docs.serverless.com/v0.5.0/docsdocs.serverless.com

※ wit.aiについては一端スルー(理由は以下)

現状

頭悪くてwit.aiの使い方/メリットがいまいち理解できず...モチベーションが下がり気味です。"音声認識"がついていること以外、単純にスプレッドシートにキーワードとそのキーワードが含まれていた場合の回答を用意しておくのと何が違うのかイマイチ理解出来ていません...。あと自分がバカなんだとおもいますがwit.ai上の単語の意図するところやインタフェースがわかりにくくてイマイチ手が進まないという。

なので、現状はmessengerでテキストを入力するとオウム返しするbotといういたっておもしろみのないサンプルで止まっています。

f:id:mitolab:20160710154847p:plain

作る上での方針

今回利用するツールはどれも新しい技術らしく、公式ドキュメント、qiita記事などの第三者情報、どちらか一方にしか無い情報があるということがネットサーフィンでわかりました。ので、「ベースの手順は公式ドキュメントを優先し、詰まったところを第三者情報に頼る」という至ってまっとうな形で進めました。

作る上でのメモ

以下は、今後同様のことをするときのために、わかりにくかった点をメモしておきます。

iamロールの設定が必要ですよ

serverlessを導入するにあたって、公式ドキュメントにあるように、"Configuring AWS"から設定しておきましょう。serverlessのプロジェクトを作る前に設定しておかないと、_meta/variables/s-variables-dev-{region名}.jsoniamRoleArnLambdaに適切なキーがアサインされず、handler.jsの実行時にエラーになりますので要注意です。

aws console iamでこんな感じになっていればOK

f:id:mitolab:20160710152220p:plain

iamロールについては、以下が分かりやすかったです。

dev.classmethod.jp

Serverless Optimizer Pluginを入れないと無理

lambdaにUPするコード(ここではhandler.js)にrequireがある場合は、browserifyしてrequire先のコードも1つのファイルにまとめるプラグインが無いと無理でした。

github.com

※ これは前述のqiita記事を読まないとわからなかったです。

API Gatewayからserverlessへのパラメータの受け渡しはどうする?

本来は、s-templates.jsonなるものを作って、任意のendpointに適用していく形のようですが、まどろっこしかったので、qiitaのサンプルのやり方を踏襲してs-function.json内で書けば動いたのでそれでいきました。

{
  "name": "facebook",
  "runtime": "nodejs4.3",
  "description": "Serverless Lambda function for project: FBBot",
  "customName": false,
  "customRole": false,
  "handler": "handler.handler",
  "timeout": 6,
  "memorySize": 1024,
  "authorizer": {},
  "custom": {
    "excludePatterns": [],
    "optimize": {
      "exclude": ["aws-sdk"],
      "transforms": [
        {
          "name": "babelify",
          "opts": {
            "presets": ["es2015"]
          }
        }
      ]
    } 
  },
  "endpoints": [
    {
      "path": "facebook",
      "method": "GET",
      "type": "AWS",
      "authorizationType": "none",
      "authorizerFunction": false,
      "apiKeyRequired": false,
      "requestParameters": {
        "integration.request.querystring.hub.verify_token": "method.request.querystring.hub.verify_token",
    "integration.request.querystring.hub.challenge": "method.request.querystring.hub.challenge",
    "integration.request.querystring.hub.mode": "method.request.querystring.hub.mode"
      },
      "requestTemplates": {
        "application/json": {
          "verify_token": "$input.params('hub.verify_token')",
          "challenge": "$input.params('hub.challenge')",
      "mode": "$input.params('hub.mode')",
          "method": "$context.httpMethod"
        }
      },
      "responses": {
        "400": {
          "statusCode": "400"
        },
        "default": {
          "statusCode": "200",
          "responseParameters": {},
          "responseModels": {
            "application/json;charset=UTF-8": "Empty"
          },
          "responseTemplates": {
        "text/plain": "$input.path('$')"    
          }
        }
      }
    },
    {
      "path": "facebook",
      "method": "POST",
      "type": "AWS",
      "authorizationType": "none",
      "authorizerFunction": false,
      "apiKeyRequired": false,
      "requestParameters": {},
      "requestTemplates": {
        "application/json": {
          "entry": "$input.json('entry')",
          "method": "$context.httpMethod"
        }
      },
      "responses": {
        "400": {
          "statusCode": "400"
        },
        "default": {
          "statusCode": "200",
          "responseParameters": {},
          "responseModels": {
            "application/json;charset=UTF-8": "Empty"
          },
          "responseTemplates": {
            "text/plain": "$input.path('$')"
          }
        }
      }
    }
  ],
  "events": [],
  "environment": {
    "SERVERLESS_PROJECT": "${project}",
    "SERVERLESS_STAGE": "${stage}",
    "SERVERLESS_REGION": "${region}"
  },
  "vpc": {
    "securityGroupIds": [],
    "subnetIds": []
  }
}

参考:

http://docs.serverless.com/docs/templates-variablesdocs.serverless.com

docs.aws.amazon.com

handler.jsはこんな感じ

'use strict';

const request = require('request');

const FB_MESSANGER_TOKEN = 'xxxxxx';

module.exports.handler = function(event, context, cb) {
  switch (event.method.toUpperCase()) {
    case 'GET': {
      if (event.mode === 'subscribe' && event.verify_token === FB_MESSANGER_TOKEN) {
        const validRequest = event.verify_token;
        return cb(null, validRequest ? event.challenge : 'Error, wrong validation token');
      }
    }
    case 'POST': {
      event.entry.forEach(function(pageEntry) {
        pageEntry.messaging.forEach(function(messagingEvent) {
      if (messagingEvent.message) {
        receivedMessage(messagingEvent);
      }
        });
      });
      return cb(null, 'OK');
    }
    default: return cb('Error, Invalid Method');
  } 
};

function receivedMessage(event) {
  var senderID = event.sender.id;
  var recipientID = event.recipient.id;
  var timeOfMessage = event.timestamp;
  var message = event.message; 

  console.log("Received message for user %d and page %d at %d with message:",senderID, recipientID, timeOfMessage);
  console.log(JSON.stringify(message));
  
  var messageId = message.mid;
  
  // You may get a text or attachment but not both
  var messageText = message.text;
  var messageAttachments = message.attachments;

  if (messageText) {
    sendTextMessage(senderID, messageText); 
  } else if (messageAttachments) {
    sendTextMessage(senderID, "Message with attachment received");
  }
}

function sendTextMessage(recipientId, messageText) {
  var messageData = {
    recipient: {
      id: recipientId
    },
    message: {
      text: messageText
    }
  };

  callSendAPI(messageData);
}

function callSendAPI(messageData) {
  request({
    uri: 'https://graph.facebook.com/v2.6/me/messages',
    qs: { access_token: FB_MESSANGER_TOKEN },
    method: 'POST',
    json: messageData

  }, function (error, response, body) {
    if (!error && response.statusCode == 200) {
      var recipientId = body.recipient_id;
      var messageId = body.message_id;

      console.log("Successfully sent generic message with id %s to recipient %s", messageId, recipientId);
    } else {
      console.error("Unable to send message.");
      console.error(response);
      console.error(error);
    }
  });  
}

誰でもbotにアクセスできるわけではない

ここまでの手順で、botサービスを一般公開できるわけではありません。一般公開するには、facebookの審査に通る必要があります。

じゃあどうやって審査に出せばいいの?というと恐らく以下のようになるかと思います。ただし実際に試したわけではないのであくまで推測になります。

  1. facebook developerの当該アプリのダッシュボードにて、左側のサイドバーからmessengerを選択し、スクショの1,2のボタンを押して申請します。

f:id:mitolab:20160710152840p:plain

  1. 左側のサイドバーからアプリレビューを選択し、page_messagingの項目でノートを編集ボタンを押します。

f:id:mitolab:20160710153411p:plain

  1. さらにその先で、プラットフォームポリシーに準拠しているかどうかの確認と、使い方のスクリーンキャストの提出を求められるので、それらを入力します。

f:id:mitolab:20160710153741p:plain

  1. 承認されれば、晴れて一般公開となると思われます。

botを誰かに試して欲しい場合はテスターとして追加する

f:id:mitolab:20160710152447p:plain

画像のように、テスターとして役割に追加してあげれば、botを試してもらうことができます。

感想

今回はとりあえず、serverlessを使ってmessengerでテキストを入力するとオウム返しするbotを作りました。感想としては、おもったよりレスポンスが遅いなー(0.5秒くらいな感覚)と思いました。handler.jsの中身の処理がかさむと恐らくもっと重くなると思われます。

wit.aiは音声認識が付いているので使いたいですが、概念を理解するのに人より多く時間を割かないといけなさそうでだるいなーというところです。

ということで、引き続き触っていきます。

ラズベリーパイ3で土壌湿度センサーを試してみました

今日はこちらの記事を参考に土壌湿度センサーを試してみました。

dev.classmethod.jp

今後はnodeで色々やりたかったので、本記事はドンピシャでした。

実験の目的

最終的には、葉物(特にコマツナ)を作るにあたっての最適な潅水タイミングを見極めたい、ので、とりあえずデータをとってみたい。

結果

結果からいうと記事の通りやったらこんなかんじで何の問題もなくデータがとれました*1

f:id:mitolab:20160529163745j:plain

f:id:mitolab:20160529163800j:plain

基本、参照元の記事の手順まんまでいけるのですが、多少僕の環境との相違点とか、補足があるのでそこだけ書いておきます。

参照記事との相違点

  • ラズベリーパイsudo raspi-configコマンドからAdvanced OptionsにてSPIの機能を有効化しました
  • 前回、nodebrewで最新のnodeを入れたので、"Node.js のインストール"は割愛しました
  • "npm モジュールのインストール"の前にサンプル用ディレクトリを作成ました
  • npm の引数 -S は--saveと同意で、package.jsonのdependenciesに追加されるので、別途package.jsonを作っておく必要があります(作り方はこちらの記事に)
  • nodeコマンドがsudoで実行できなかったので、nodebrewがインストールした場所(which nodeで特定)からシンボリックリンクを貼って対応しました(参考)

参照記事の補足

ピン名対応表

記事中Fritzingで書かれた図面を見れば、配線はできますが、ADコンバータとラズパイ上のピンの対応関係が把握しずらかったのでここで少し補足します。

土壌湿度センサー 結線 MCP3208-CI/P 結線 ラズベリーパイ3
青:
湿度出力(アナログ電圧出力: 0~4.2v(@5v))
- Pin1:
CH0
赤:
電源入力(DC3.3~5v)
- - Pin2:
5v Power
黒:
GND
- Pin14:
AGND*2
- Pin6:
Ground
Pin16:
ADO*3
- Pin1:
3.3v Power
Pin13:
CLK
- Pin23:
SPI0 SCLK
Pin12:
Dout
- Pin21:
SPI0 MISO
Pin11:
Din
- Pin19:
SPI0 MOSI
Pin10:
CS/SHDN
- Pin24:
SPI0 CE0

※ 結線に"-"(ハイフン)が入っているものは結線します。MCP3208-CI/Pを飛ばして結線しているものもあります。

※ MCP3208-CI/PのPin10は、LOWにするとADCがONの状態になります。ADCを使わない場合はHIGHにしてて待機状態にする必要があります。

出力される数値の対応

土壌湿度センサーの開発元wikiページ)をみると、

0 ~300 : dry soil
300~700 : humid soil
700~950

とありました。これはArduinoに繋いだ場合の値で、見たところ上限が10bit(0~1023)ぽいです。今回のADCは12bit仕様なので、分解能は0~4095になります。これを直線的に変換するとすれば、

出力値 状態
0~1292 乾いている
1292~3017 湿っている
3017~4095 湿りすぎ

というふうになるかとおもいます。

通信方式について参考

今回使ったSPI通信、前回のI2C通信に関してはこちらが参考になるかと思います: I2CとSPI

感想

センサー自体が"プリント基板を切り出しました" みたいな作りだったことや、ウルトラ簡単な回路ということもあったりで実用性はどうなんだろう...というところです。色々他も調べてみたほうがいいかもしれません。

また、pFメーター(テンシオメーター)とはちがって、植物の根と土壌間の水分浸透圧を加味することはできないので、その辺の相関関係を調べないと、根が水分を吸収するのに最適な潅水時期を検出することはできないかなぁと思いました。その辺は、東大の難しめな資料が参考になるかもしれません。

あと、良く硝酸態チッソの量を推測するのに使われるEC(電気伝導率)とは仕組みとしてはどう違うのだろうと疑問に思いました。

ということで、かなり簡易的なデバイスですがデータは取るだけとってみて考えようと思います。

*1:ハウツーを参照させていただいたクラスメソッドさんありがとうございます

*2:Pin9:DGND と直結

*3:Pin13:AREF と直結

ラズベリーパイ3にnodejsをインストール

前回のセンサの動作確認pythonでやったんですが、今後はpythonじゃなくてnodejsで色々やりたいので、とりあえず環境を整えます。

既存のnodejsをアンインストール

# apt-getでインストール済のパッケージを確認
dpkg -l | grep node

# nodejs, nodejs(legacy), nodered が入ってたのでそれぞれアンインストール [参照](http://kawatama.net/web/296)
sudo apt-get --purge remove nodejs
sudo apt-get --purge remove nodered

# 一応ちゃんと削除されたか確認
dpkg -l | grep node
sudo find / -name node

# proc/xx/node ってファイルが大量にあったけど問題なさそうなので続行

nodebrewをインストール

# nodebrew(nodeのバージョン管理)をインストール
curl -L git.io/nodebrew | perl - setup

# nodebrewのパスを通す
vim ~/.bashrc
export PATH=$HOME/.nodebrew/current/bin:$PATH
source ~/.bashrc

# nodebrewが有効になったか確認
nodebrew -v

# nodebrewでnodejsのバイナリ安定版をインストール(もし無ければbinaryを外してみる。ちなみにバイナリじゃない場合はソース落としてコンパイルするのでクソ時間かかります要注意)
nodebrew install-binary stable

# lsして出てきたものをuse
nodebrew ls
nodebrew use v6.2.0

# 上記versionが出てきたら成功
node -v

とりあえずここまで。

Raspberry Pi3でTSL2561照度センサの動作確認

こちらの記事を見ながらやってみたらあっけなく動きました。。

qiita.com

boyaki_machineさんありがとうございます。

唯一相違点としては、snd-bcm2835の記入は特に必要なかったです。オーディオのモジュールのようですが、これはデフォでうごいているようでした。lsmod | grep snd_bcm2835 すれば分かります。

f:id:mitolab:20160523215706p:plain

今後としては

  • pythonで動いているんですがnodejsで統一したい
  • High Gainにした時、ある程度の照度(5月日中の窓際くらい)があると異常な値に固定される らしいのでその点を確認してみる

という感じでしょうか。とりあえず動作確認ということで。

Rasberry Pi3にRaspbianをインストールしてSSHでつなぐとこまで

やろうとしていること

f:id:mitolab:20160523185459p:plain

今後各種センサを繋いで開発を行う*1ので、まずは開発しやすい環境を、ということで自宅などで自分のメインマシン(macPC)からSSH接続できるようにしたいと思います。

尚、自宅にHDMIモニタや外付けUSBキーボードが無いので、macPCでSDカードにOSイメージ(raspbian)を焼いて、それをラズパイ3に読ませるという手法をとりました。

必要なもの

  • macPC
  • Rasberry Pi3(以下ラズパイ3)
  • MicroSDカード(コレを使いました)
  • SDカード変換アダプタ(macPCのスロットがSDカード用なので)
  • 電源(5V, 1.2A以上)
  • LANケーブル
  • 無線LANルーター

HDMIモニタ、キーボードは使いません

手順

公式サイトでOSイメージをDL

公式サイトDLページ

f:id:mitolab:20160523185527p:plain

左がDesktop版、右がミニマル。大は小を兼ねるということで左を選択。サイズは約1.4GBでした。

1. DLしたOSイメージが正常か確認する(チェックサムのdiffを取る)

  1. 上記DLサイトにSHA1キーが記載されています。そちらをコピーしてCS_site.txtとかいう名前で保存します
  2. DLしたzipファイルのチェックサムを別ファイルに保存します: shasum 2016-05-10-raspbian-jessie.zip > CS_DL.txt
  3. 1と2で作成したファイルの差分をとります: diff CS_site.txt CS_DL.txt

特に差分がでなければOK、差分がでたらダウンロードしたデータに異変があるので、再度ダウンロードするなりします。

2. OSイメージをmicroSDカードに焼く

  1. macのSDカードスロットにmicroSDカード装着済のSDカードアダプタを挿入
  2. terminalを開いて以下の要領でマウント
## SDカードのエンドポイントを探す。僕の場合は `/dev/disk2` でした
diskutil list

## 一度アンマウントします(マウントされた状態だとOSイメージを焼くddコマンドが使えないので)
sudo diskutil unmountDisk /dev/disk2

## OSイメージのzipを解凍します(普通にFinderからダブルクリックで解凍でもOK)
cd ~/Downloads
unzip 2016-05-10-raspbian-jessie.zip

## OSイメージをmicroSDカードに転送します
sudo dd bs=1m if=2016-05-10-raspbian-jessie.img of=/dev/rdisk2

## 転送中、様子を見たいときはctrl+tで進捗状況を確認できます

3. ラズパイ3にsshで接続する

前準備

  1. 上の手順でOSイメージを入れたmicroSDカードをラズパイ3のmicroSDスロットに挿します
  2. ラズパイ3に電源をいれます。5V 1.2A必要らしいですが、僕はこのモバイルバッテリーを使いました。

ラズパイ3のIPアドレスを取得

  1. macPCのterminal上からarp -a > before_ips.txtを実行してラズパイ接続前のIP一覧を取得します
  2. 無線LANルーターにラズパイ3をLAN接続して30秒くらい待ちます
  3. macPCのterminal上からarp -a > after_ips.txtを実行してラズパイ接続後のIP一覧を取得します
  4. diff before_ips.txt after_ips.txtとして出てきたIPアドレスが恐らくラズパイ3のIPです

上記ででなければ、新しいIPが大抵新しく追加されたIPなので総当りしてみます。

ssh接続

ラズパイはデフォルトでsshが有効になっているとのことで、上記4の手順で取得したIPを用いて以下のようにssh接続します。

## パスワードはデフォルトだと raspberry でxの部分は上記で取得したIP
ssh pi@x.x.x.x

無事接続できると以下のようになります。

f:id:mitolab:20160523202637p:plain

参考

Raspberry Pi 2 Model BのOSインストールと初期設定 https://www.generation.ne.jp/topics/raspberry01/

Mac OS X で Raspberry PiのOSイメージを焼く http://ledsun.hatenablog.com/entry/2014/10/26/174712

DDコマンド http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230741/