IT + X

ITと何かのコラボレーションは時代を変えるかも

JAMStackをいまさらながら解説してみる

最近、JAMStackという考え方を、遅まきながら知りました。
静的サイトジェネレーターは昔から知っていましたが、CD/CIやBaaSなどと組み合わさってこんなに進化していたのは驚きでした。
ということで、JAMStackについて調べた内容をまとめてみました。

JAMStackとは

JAMStackとは、静的ファイル(HTML, CSS, Javascript)を基本とした新しいタイプのウェブアーキテクチャーです。
ちなみに、JAMStackのJAMとはJavascript + API + Markupの略です。

現在のメジャーなCMSは、ウェブサーバーとDBサーバーの連携により構成されています。
WordPressDrupalといったCMSが有名ですね。
なので、ユーザーがブラウザでアクセスするとウェブサーバーがDBサーバーに問い合わせてHTMLを返します。

f:id:anthony-g:20210609145504p:plain

この構成は、ダイナミックなウェブコンテンツを生成するのにはいいのですが、リクエストのたびにDBアクセスが発生するのでサーバー負荷が高くなります。

JAMStackは、データ登録時HTMLを生成しHTMLファイルなど静的ファイルのみでコンテンツを構成します。

f:id:anthony-g:20210609163810p:plain

上の図では、まず最初に記事データをGitHubなどのバージョン管理システムにプッシュします。
すると、静的サイトジェネレーターというHTMLを生成するプログラムが自動で実行されます。
生成されたHTMLファイルはCDN(コンテンツ配信システム)に配置されます。
JAMStackでは、静的ファイルのみで構成されてデータベースとの接続は行いません。
ただし、動的コンテンツが必要なこともありますので、ウェブAPIを公開するサードパーティサービスを利用します。

JAMStackのメリット

では、WEB+DB方式より優れているJAMStackの点はところはどこなのでしょうか?

  • CDNでの運用の容易さ
    JAMStackは、基本的に静的ファイルのみを扱いますので、CDNへファイルをアップロードするだけで運用が簡単です。
  • スピード
    DBアクセスがないので、ユーザーからのアクセスにも素早く返すことができます。大規模なアクセスが集中するサイトに向いていますね。
  • セキュリティ
    既存のCMSは、複雑なプログラムになってしまっているのでセキュリティの脆弱性がしょっちゅう出ます。しかし、JAMStackはその心配がありません。
  • バックアップ
    静的ファイルだけで構成されているのでバックアップも簡単です

ただ、JAMStackにも向いていない分野があります。

  • 更新頻度
    プラットフォーム系サービスなどコンテンツがしょっちゅう更新されるようなサイトだと、頻繁に静的ファイルのリビルドが走ることになるので向いていません。ただ、ヘッドレスCMSというサービスを使えば問題はありません。

  • コーディングの必要性
    後ほど説明しますが、静的サイトジェネレータというプログラムを実行することになりますので、エンジニアでないと運用できない部分が増えることになります。

JAMStackを実現する技術

JAMStackは、いくつかの要素技術によって構成されています。

  • 静的サイトジェネレーター
    JAMStackでは、最終的にHTMLやCSS, Javascriptなどの静的ファイルを生成しますが、それを行うのが静的サイトジェネレーターです。
    静的サイトジェネレーターとして有名なものは以下のようなものがあります。

Gatsby.js
www.gatsbyjs.com

Hugo
gohugo.io

Jykill
jekyllrb-ja.github.io

  • CD/CI
    プログラム開発では、CD(継続デリバリー)/ CI(継続インテグレーション)は当たり前ですが、ウェブコンテンツ制作でも必須のものとなりそうです。
    JAMStackが可能になったのは、CD/CIサービスが充実したことも理由の一つと言えるでしょう。
    有名なCD/CIサービスとしては、GitHubやBitBucketなどがあります。

  • CDN
    CDNコンテンツ配信ネットワーク)の普及もJAMStackには重要な要素です。
    CDNは、効率よくコンテンツを配信するしくみで多くの大規模ウェブサイトで利用されています。
    JAMStackは、CDNの使用が前提となる技術となっています。

  • Web API
    静的ファイルのみではダイナミックなコンテンツを提供することができません。
    データ更新毎に静的ファイルを生成するという方法もありますが、あまり現実的ではありません。
    そんな時は、APIを公開している外部サービスを利用します。
    現在では、認証や決済、CMSなどの機能を公開しているサービスがたくさんあります。

JAMStackエコシステム

https://miro.medium.com/max/700/1*TdRFV0LAG7TG3US2YJMALA.jpeg

ここにきてJAMStackが話題になったのは、様々な関連サービスによって構成されるエコシステムが実用レベルになってきたのがあります。
上の図のように、現在では様々なフレームワークやサービスが提供されています。
この中で、いくつか注目のサービスについて解説しましょう。

Netlify

www.netlify.com Netlifyは、JAM Stackという言葉を考えた会社で、提供するサービスもJAM Stackに特化したものになっています。
無料プランで色々できますので試しに使ってみてはいかがでしょうか。

Firebase

firebase.google.com Googleが提供するBaaSと呼ばれるサービスで、認証やデータ保存、Web API公開などが手軽に利用することができます。
詳しくはこちらのブログ記事で解説してますので、よかったら読んでみてください。

blog.it-plusx.com

AWS Amplify

aws.amazon.com Amazon AWSが提供するNetlifyとFirebaseが一緒になったようなサービスです。
AWSの他のサービスとシームレスに連携できるので、AWSを利用しているユーザーには便利なサービスです。

駆け足でJAM Stackについてまとめてみましたが、イメージできましたでしょうか。
まだまだWordPressなどの従来のウェブシステムが主流な状況ですが、これからはJAM Stack型のサイトが増えていくものと思われます。
ITエンジニアならぜひともキャッチアップしておきたい技術ですね。

ITエンジニアになりたい人が就職する前に学んでおくべきこと

最近、ITエンジニアになりたいという若い人のツイートをよく見ます。
私がITエンジニアなりたてのころは、未経験でも雇ってくれる会社は結構あってITエンジニアになりやすい時代でした。
しかし、PCやソフトウェアは高くて、Unixマシンは数百万以上していて個人で買えるようなものではありませんでした。
それに比べれば、今はPCは20万も出せば最高スペックのものが買えるし、開発ツールもほぼ無料で使うことができます。
また、書籍やネット上の情報もたくさんあって、自分でいくらでも学ぶことができるのでいい時代になったなと思います。

ただ私もそうでしたが、全くの初心者だと何から学べばいいかわからないので、高額なスクールに行く人が多いのでしょう。
しかし、何を学ぶべきかわかれば独学で安く学ぶことができます。
ということで、初心者の方がITエンジニアとして就職する前に学んでおくべきことをまとめてみました。

私がエンジニアになったころは、仕事をしながら勉強するしかなかったのですが
日々の業務を行いながら学ぶのはかなりきつかったです。
なので、事前に必要なことは学んでおくことをお勧めします。
ただ、プロジェクトによって必要なスキルは変わってきますので、最大公約数的なこれは学んでおくべきことだろうと思われるものを選びました。
それでも、結構な量になってしまいましたが。
とりあえずは、一般的なソフトウェア開発(ウェブ、業務システム)を行うエンジニアを想定しています。

プログラミング言語

初めて学ぶ言語は何でもいいと思います。
なぜなら、どのプログラミング言語も同じような機能であることが多いからです。
ただ、学びやすい言語を選んだほうがいいでしょう。

初心者におすすめの言語はC#です。
理由は、C#は今どきの言語が備えておくべき機能を装備していて、文法にクセがなく、プログラムロジックに集中できる言語だからです。
その上、C#の開発用IDEであるVisual Studioがよくできていて、エディタで編集している時にスペルミスなど単純なエラーは教えてくれるのでコーディング効率は高いです。

また、ウェブ開発ではJavascriptが必ず必要になりますが、最初にやる言語としてはおすすめしません。
なぜなら、言語として結構クセがあり、型のない言語なのでデバッグがしづらいという性質があります。
なので、Javascriptはプログラミングになれた頃に学ぶのがいいでしょう。

プログラミング言語は、自分で書いて動かしてみないと習得できませんので、
本で大体の書き方を理解したらどんどん自分でプログラムを書いてみましょう。

C#Javascriptのおすすめ書籍

開発ツール

プログラム開発を行う上で開発ツールを使うことは必須のスキルです。
その中でもエディタは、必ず必要になる開発ツールです。
Visual Studio CodeなどのGUIベースのエディタも人気がありますが、
エンジニアであればVimをマスターしておいたほうがいいでしょう。
なぜなら、Linuxサーバーのようにターミナルでしか作業できない環境でも、Vimは必ずインストールされています。
キーバインドも慣れるととても使いやすいので、ぜひVimをマスターしておいてください。

また、ソースコード管理のGitコマンドの使い方も、ITエンジニアならマスターしておくべきです。
さらに、今どきのソフトウェア開発ではGitHubを使うことも多いので、プルリクエストやイシュー管理なども使いこなせるようになっておきたいところです。
GitHubと合わせてJenkinsやCircle CIなどのCD/CIサービスにもなれておいたほうがいいでしょう。
CD/CIサービスとは、GitHubと連携して自動でテストやデプロイを行うためのサービスです。
CD/CIによって開発効率は格段に上がりますので、知識だけでなく使いこなせるようになっておきましょう。

エディタ、GitHubのおすすめ書籍

データベース

データベースは、あらゆるプロジェクトで必ず扱うことになる技術です。
主に、プログラムからDBに対してSQLによる問い合わせを行うことになるので、
DBの基本とSQLの書き方については熟知しておくべきでしょう。
また、DB設計は経験のあるDB専門のエンジニアが行うことが多いですが、
できればDB設計できるくらいの知識も学んでおいたほうがいいでしょう。

データベース、SQL

達人に学ぶDB設計 徹底指南書

達人に学ぶDB設計 徹底指南書

ネットワーク

現代のITシステムは、スタンドアロンで使われることは少なく、
ほとんどがネットワークに接続されていて、プロトコルとしてTCP/IPが使われています。
また、通信系のプログラムでは、パケットキャプチャーソフトなどによってどのようなやりとりが行われているか見る必要がある場合もありますので、パケットキャプチャーデータの見方も学んでほしいところです。
TCP/IPの知識も、ITエンジニアにとって必須の知識ですね。

TCP/IPのおすすめ書籍

サーバー

サーバーは、どちらかというとインフラ系エンジニアの範囲だと思われていますが、
サーバー側のプログラムを作る時は、サーバーについて知っておく必要があります。
まずは、Linuxサーバーについて学んでおいて、余裕があればWindowsサーバーにも挑戦してみましょう。

サーバーのおすすめ書籍

コンピュータアーキテクチャ

コンピュータの構造や基本となる理論についての知識が、実際の仕事で必要になることはありませんが コンピュータがどのように動いているかについての基礎知識は学んでおいたほうがいいと思います。
「コンピュータシステムの理論と実装」では、ハードウェア部分のデジタル論理回路からOSまでを網羅した内容になっていて
コンピューターの動作がイメージしやすい内容になっているのでお勧めの本です。

コンピュータアーキテクチャのおすすめ書籍

アルゴリズム

アルゴリズムも、実際のプロジェクトで必要となることは少ないですが、
これも基礎知識として学んでおいたほうがいいでしょう。
「問題解決力を鍛える!アルゴリズムとデータ構造」という本がC++で解説してますので、ついでにC++も学んじゃいましょう。

アルゴリズムのおすすめ書籍

スラスラわかるC++ 第2版

スラスラわかるC++ 第2版

セキュリティ

ITシステムを構築する上で、セキュリティはいまや最も優先度の高い問題となっています。
ウィルスやデータ改ざん、盗聴などいまやITシステムは様々な脅威にさらされています。
ITエンジニアとして、セキュリティに関する知識も必須と考えるべきでしょう。

セキュリティのおすすめ書籍

セキュリティ技術の教科書 第2版 (教科書シリーズ)

セキュリティ技術の教科書 第2版 (教科書シリーズ)

  • 作者:長嶋 仁
  • 発売日: 2020/03/18
  • メディア: 単行本(ソフトカバー)

設計方法
ソフトウェアを開発するためには、プログラミング言語を習得するだけではだめで
どういう構成にするかが重要になってきます。
今どきのプログラミング言語オブジェクト指向言語ですので、クラスやオブジェクトをどう設計するかというオブジェクト指向設計について知っておく必要があります。
また、そのオブジェクト指向設計でよく使われるパターンはデザインパターンとして整理されています。
仕様変更に強い設計を行うために、オブジェクト指向設計デザインパターンも学んでおくべきトピックです。

設計関連のおすすめ書籍

プロジェクト管理
プロジェクト管理というとプロジェクトマネージャーの仕事だと思われがちですが、
エンジニアもプロジェクト管理について知っておく必要があります。
なぜなら、大抵のプロジェクトは予算も期間もギリギリであることが多く、
途中で仕様変更を押し込まれることが多いので、理不尽な要求ははねつけるためにも理論武装が必要になります。
そして、不確定性の高いプロジェクトではアジャイル開発やスクラムといった方法論が使われることが多くなりました。
デスマーチプロジェクトに巻き込まれないためにも、プロジェクト管理についてはエンジニアも知っておくべきです。

プロジェクト管理のおすすめ書籍

英語
今や日本語のIT情報は、書籍やネットから多く得られるようになっていますが、最新の情報など英語での発信がメインとなっている情報もたくさんあります。
特に、詳細な技術情報は英語でしか得られないことが多いので、英文を読めるスキルはエンジニアには必須のスキルとなっています。
さらに、文章を書いたり会話することができるようになるのがベストですが、まずは英文を読めるように努力してみましょう。
ただ、外国語の習得はテスト勉強のように短期集中でできるものではなく、長い時間をかけてたくさんの文章に触れる必要があります。
なので、興味のあることを英文でたくさん読んでみましょう。
「Hackers」は、マイクロソフトやアップルがシリコンバレーでどのように起業されたかの歴史を解説した内容になっていて、日本語訳も昔出ていました。
ITエンジニアには興味深い内容になってますし、Kindleだと電子辞書が使えるのでわからない単語を調べながら読んでみてください。
根気強く読んでいれば、いつの間にかスラスラ読めるようになるのでがんばってください。

Hackers

結論

かなり盛りだくさんになってしまいましたが、ITエンジニアをめざすならこれくらいは学んでほしいところです。
ただ、全てを完璧に理解しようとせず、どれか一つを深くやって他はおおまかな知識だけでも頭にいれるようにすればいいと思います。
ソフトウェア開発エンジニアだと、プログラミング言語と設計あたりを中心にやったほうがいいでしょう。
そして、就職したあとに他の分野も深めていけばいいと思います。
基礎がしっかりしているエンジニアになるには時間がかかるものですが、技術が変わってもキャッチアップして息長く働けるエンジニアになれるでしょう。
ぜひ、そんなエンジニアを目指してください。

最後に、ITアカデメイアというITエンジニア向け学習動画サイトをやっています。
これからITエンジニアになりたい方向けのコンテンツを提供していますので、よかったらチェックしてみてください。

ITアカデメイア https://www.it-akademeia.jp/ www.it-akademeia.jp

Hands-On Machine Learning with Scikit-Learn Keras & TensorFlow Ed.2(イントロ)

Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems

Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems

機械学習の教科書的テキストとして評判のHands-On MLの第2版(英語版)が出たので早速買って読んでみました。 構成としては基本的に第一版と同じようですが、TensorFlowなどのライブラリバージョンアップに伴って内容がアップデートされているようです。 日本でも第一版は翻訳されていますが、翻訳がまずいのかイマイチ評判はよくないようです。

実は第一版はかなり前に読んだのですが、あまり理解できないところが多かったので第2版に改訂されたのを期にもう一度再読してみようと思います。
読んだ内容は何回かに分けてまとめていきたいと思います。

まず、本の内容は全体的にこのような構成になっています。

機械学習の基本知識

ニューラルネットディープラーニング

全体的に前半が非ニューラルネットアルゴリズムについてに書かれていて、後半はニューラルネット/ディープラーニングという構成になっています。
ちょっと読んだ感じでは、今回の改訂で変更、追記されたのは主に後半部分ではないかと思います。

サンプルプログラムはこちらのURLからダウンロードできます。
Jupyter Notebook形式になってますので、実行結果を確認しながらコードを読むことができます。
ハンズオンと本のタイトルにもあるように、実際にコードを動かすことを基本とする内容なので、ぜひとも自分のPCに実行環境を作って動かしながら読み進めてください。

では、まず初回ですので実行環境を作る説明をします。
私の実行環境はMacですが、他のプラットフォームでもそんなに違わないと思います。
まず、Pythonをインストールする必要がありますが、おすすめはAnacondaというパッケージシステムを使うことです。

www.anaconda.com

AnacondaはPythonだけでなく、いろんなライブラリを簡単にインストールできるディストリビューションです。
機械学習関連のライブラリが充実していて、アップデートもコマンドで簡単にできます。
上のURLからPython3のバージョン(2019年11月現在Pythonのバージョンは3.7)のインストールイメージをダウンロードしてください。
ダウンロードファイルは、インストールプログラムになっているので実行してインストールします。
ターミナルを開いて、Pythonがインストールされていることを確認します。

% python -V
Python 3.7.3

前にダウンロードしたサンプルファイル(handson-ml2/)内にrequirements.txtというファイルがあります。
これは、サンプルコードを動かすために必要なPythonライブラリの情報が書かれています。
requirements.txt

...
##### Core scientific packages
jupyter==1.0.0
matplotlib==3.1.1
numpy==1.17.2
pandas==0.25.1
scipy==1.3.1
....

以下のコマンドでrequirements.txtに書いてあるライブラリを一気にインストールできます。

% conda install --yes --file requirements.txt

ただ、requirements.txtはpipというコマンドの形式なのでcondaでインストールするとパッケージが見つからないと言われることがあります。
その時はpipコマンドで個別にインストールします。

% pip install [ライブラリ名]

サンプルコードはJupyterノートブックという形式になっています。
これはブラウザ上でPythonを動かせる環境で、実行結果がブラウザ上に表示されるので試すのにとてもいいです。

handson-ml2ディレクトリ内でJupyter Notebookを起動します。

%  jupyter notebook

ブラウザでhttp://localhost:8888にアクセスすると以下のページが表示されます。

f:id:anthony-g:20191126140054p:plain
Jupyter Notebook

次回からいよいよ内容について書いていきたいと思います。

(おまけ)ディープラーニングを学んで思ったこと

前のエントリーでディープラーニングについて書きましたが、学ぶ中で思ったことや考えたことが色々あったので書いておこうと思います。

ニューラルネットはソフトウェアのイノベーション

今までのソフトウェアは、人間がいちからプログラムを書かないと正しく機能しませんでした。
しかし、ニューラルネットではデータを与えることによって自ら改善していくようになったことはエポックメイキングなことだと思いました。
ある意味、いままで実現できなかった自動プログラミングが可能になったということだと思います。
これが進化すれば、プログラミングさえもコンピューター自身が行うこともいずれ可能になるでしょう。
ソフトウェア開発だけでなく、あらゆるものの製造やデザイン、研究などもできるようになるかもしれません。
もちろん、全てをコンピューターに代替するのは難しくて、物事の善悪を判断したり文化的背景を考えたりすることは難しいと思います。
ただ、コンピューターに依存する場面はこれからますます増えていきますので、すべての人がコンピューターについて正しい知識を持つ必要がある時代になっていくのではないでしょうか。

バイスの進化がイノベーションを可能にする

ディープラーニングの技術は最近出てきたように思われているかもしれませんが、元々のアイデアは40年前に考えられていたのですが(しかも日本人!)いろいろな意味で早すぎたため注目されませんでした。
それが、半導体チップの集積率が上がって実現可能な技術となったため一気に知られるようになりました。
一見華やかなイノベーションも地道な努力があったから可能になったということなのでしょうね。
昔、私がPCをはじめて買った頃はゲームしかできない高いおもちゃで役に立たないとさんざん言われましたが、ここまで来るとは想像もできなかったです。

学習が一番負荷がかかる

機械学習で一番負荷のかかるのは学習です。
大量のデータを用意するのも大変ですが、それをニューラルネットに入力して学習させるのにかなりのCPUパワーが必要です。
そこで機械学習に特化したチップやGPUなどを使って高速化する技術も出てきました。
アプリケーションによってデバイスにも技術革新が起こるという点で興味深い現象です。
そんな機械学習を学んでいると、ふと人間の学習についても考えるようになりました。
人間でも小中高大と16年もかけて学習していますが、そんなに長期間かけてるのにちゃんと学習できているのかと思いました。
テストで点数を取ることばかり気にして本当の理解ができていないのではないか、それは機械学習で言えばテストが通るようなモデルを作っているのと同じだと思います。
機械学習には過学習という問題があって、特定のデータに最適化された学習が行われると正しい判断ができないモデルになってしまうことがあります。
人間の教育もあまりにもテストを重視するために過学習状態になっている人が多いのではないでしょうか。
最近の日本のエリートの劣化を見ると、そんなことも考えてしまいました。
技術から人間のあり方が洞察できるというのもおもしろいですね。

多くの試行錯誤がいいモデルを作る

機械学習では、バッチでひとまとまりのデータを複数回与えてニューラルネットを改善していくことが基本動作になります。
なので、最初は赤ちゃんと同じで何もできない状態ですが、試行錯誤しながら学習することによってうまく処理できるようになっていきます。
ここで思ったのが、日本社会はこの対局にあるなということでした。
学校でも減点主義でミスするとバッテンをくらいますし、企業ではミスすると左遷されたり給料査定を下げられたりします。
こういうことをすると学習する機会を奪われることになります。
一般にはディープラーニングは話題になっていますが、今の日本社会では受け入れられない技術ではないかと思います。
特に、日本企業は終身雇用で長く働いている人が多いので、自分が用済みになりそうな技術を積極的に入れようとは思わないでしょう。
そういう意味で私は日本社会には絶望していますので、機械学習でビジネスするのなら海外がいいのではないかと思っています。

ブラックボックスではない

AIはブラックボックスで中身がわからないとよく言われますが、これは正しくありません。
前のエントリーでも説明したとおり、ニューラルネットのキモはニューロン間の接続の重みデータです。
これは見ることはできますが、ただの数値の羅列なので人間がその意味を理解できないだけです。
しかし、それをわかりやすく表示するツールや挙動を分析するツールなども出てきてますのでこれからだんだんと可視化されるようになるのではないかと思います。
なので、怖がるのではなくちゃんと理解して付き合うことが大事だと思います。

ちょっとエッセイ風に書いてみましたが、いかがだったでしょうか?
私はディープラーニングをインターネット以来のイノベーションだと思っています。
そして、単に技術的な進歩というだけでなく、仕事がなくなったり誤った使われ方をするなどの負の側面を考えることによって、これから人はどうあるべきなのかを考える機会にもなるのではないかと思います。
いずれにしても機械学習によってよりよい社会になってほしいなと思います。

ディープラーニングは難しくない

ディープラーニングという言葉は今では専門家だけでなく多くの人が知るようになりました。
自動運転車や顔認識などニュースや身の回りで使われるようになっているから広く知られるようになったのでしょうが、ディープラーニングがどのようにして動いているのかエンジニアでも知らない人も結構います。
今回、集中的にディープラーニングについて学んだのでそのまとめと学んでいて感じたことを書いておこうと思います。

まず、ディープラーニングを学ぼうと思った時に本屋さんで色々見てみたのですが、その多くが数学の教科書みたいなものばかりでした。
大学で発展してきた技術なので仕方ないのでしょう。
しかし、実際に学んでみて思ったのが、線形代数や確率などの数学は使う分にはそこまで数学は必要ではなく、実際のプログラムではライブラリが難しい部分をやってくれるのでがちで数学が必要なところはそんなにありません。
後、ほとんどの本が詳細なところにフォーカスしていて全体的にイメージしにくいと思いました。
著者が学者かエンジニアの人ばかりなので細かな所に気が行ってしまうのでしょうが、私のような初心者には全体をイメージできるほうが理解がしやすいなと感じました。
そんな中で比較的理解できたのが次の2冊でした。

この本はPythonを使ったディープラーニングの本ですが、極力ライブラリを使わず底辺から作っていくスタイルなのでディープラーニングのしくみを学ぶにはとてもいいと思います。
数学の記述も多少ありますが、高校レベル+線形代数の基礎くらいで読みとけるのでそんなに難しくないと思います。

PythonとKerasによるディープラーニング

PythonとKerasによるディープラーニング

この本もPythonを使っていますが、TensorFlowやKerasなどのライブラリを使っています。
前の本はゼロから作っていましたが、こちらの本ではライブラリを使うので実践で使うにはこちらのほうがいいかもしれません。

後、ネットの情報などでも色々学んでみて思ったのはディープラーニングの基本的なアイデアは単純だということでした。
ディープラーニングの元となるニューラルネットのアイデアは20年以上前からあったらしいのですが、最近ブレイクしたのはコンピュータの処理能力が上がったからでした。
なので、色々学ぶことは多いですが基本はシンプルですので理解するのはそんなに難しくないと思います。
では、ディープラーニングについて詳しく説明していきましょう。

ニューロン

ディープラーニングの元々のアイデアは生物の脳の研究が元になっています。
未だに生物の脳がどう動いているかは解明されていませんが、その基本要素である神経細胞ニューロン)はどう動いているかはわかっています。
f:id:anthony-g:20190927123555p:plain この図のようにニューロンは電気信号を伝える細胞で、複数の入力と一つの出力を持つ素子になっています。
そして、入力信号がある閾値を越えるとニューロンが発火し信号を出力します。
ディープラーニングはこのアイデアを元にコンピューター上で実現された技術です。

ニューラルネット

では、このアイデアディープラーニングではどう使われているのでしょうか?
ここでニューラルネットというものが出てきます。
ニューラルネットとは、ニューロンを複数束ねてそれぞれを信号線で接続した形のものを言います。
下図のようなものが一例です。

f:id:anthony-g:20190927124302p:plain

ニューロンを複数持つグループが層になっていてそれぞれ接続されているものをニューラルネットといいます。
図のように入力層、隠れ層、出力層と呼ばれる層で構成されていてこの順番で信号が流れます。
この隠れ層が100以上持つようなニューラルネットディープラーニングでは使われます。
当たり前ですが、この層が増えるに従ってマシンパワーが必要になります。
ディープラーニングがコンピューターの能力が上がらないと実現できなかった技術であることがこれで理解できると思います。

ディープラーニングワークフロー

ディープラーニングでは、データを読み込んで学習し、学習結果が正しいかをテストした後にAIとして使えるようになります。
ディープラーニング入門でよく使われる手書き文字認識の例で具体的に説明します。 まず、コンピューターに学習させるために教師データというものを用意します。
この例では、教師データは手書き文字画像とそれがなんの文字であるかを表すラベルがペアになっています。
その教師データをニューラルネットに大量に入力します。

f:id:anthony-g:20190927131627p:plain

この学習の処理がディープラーニングで一番負荷のかかる処理です。
学習の結果、ニューラルネットが手書き文字認識のために最適化されますので、それがちゃんと正しいかをテストします。
テストデータは学習したときと同じ形式のデータを使いますが、データ内容は別のものを用意します。
なぜなら、学習データに都合のいいニューラルネットになっていないかをチェックするためです。
ニューラルネットには過学習という問題があり、特定のデータに過度に最適化されると違うタイプのデータをうまく処理できなくなるからです。

f:id:anthony-g:20190927132458p:plain

何を処理するかにもよりますが、正解率99%以上が現実に使えるニューラルネットのようです。
そして、テストで問題なければ実際のデータで画像認識を行います。

f:id:anthony-g:20190927133107p:plain

これが一般的な機械学習処理のワークフローになります。
では、ニューラルネット上で学習処理はどう行われているのかを次に説明します。

学習とはニューラルネットの重みデータの最適化

前にニューラルネットは層で別れていてニューロン同士が接続されている構成をしていると説明しました。

f:id:anthony-g:20190927124302p:plain

この図ではニューロン同士がフルメッシュで接続されていますが、特定のニューロンの接続だけを取り出したのが次の図になります。

f:id:anthony-g:20190927133906p:plain

b, x1, x2のニューロンとyのニューロンが接続されていて、b, x1, x2から入力されたデータがyで出力されるということを表しています。
ここで大事なのがw1, w2という値で「重み」と呼ばれている値です。
これはニューロン間の接続に付随する値で、w1はx1にかけられw2はx2にかけられます。
ちなみにbはバイアスと呼ばれていてニューロンの発火のしやすさを制御します。
この例では右にある方程式の計算が行われて計算結果が0より大きければyは1、0以下ではyは0となるニューラルネットを表しています。
先程の手書き認識の例でいうとx1,x2は入力画像データです。
そして、w1, w2は学習処理のときに設定されます。
つまり、機械学習とはこの重みデータを最適な値に設定する処理のことをいいます。
これはすごくシンプルな考え方だと思いませんか?
私が最初にこのことを理解したとき、機械学習ってこういうことなのかと目からウロコでした。
つまり、重みの値を変えることによって手書き文字が読めるようになったり翻訳できるようになったりするのです。
実際は、後で説明するように特殊なニューラルネットを使ったり速度を上げるためのテクニックとかあるのですが、基本はこれです。
これを抑えておけばあとはTipsみたいなものと考えていいと思います。

あともう一つ説明しなければいけないのが活性化関数についてです。
前に、ニューロンは入力によってしきい値を越えると発火すると言いました。
したがって、どのような値で発火するか判定する関数を定義する必要があります。
それが活性化関数です。
上のニューラルネットの図のyのニューロンで重みをかけて計算した結果を活性化関数に渡しています。

f:id:anthony-g:20190927154640p:plain

上図の右の方程式は、重みによる計算結果を活性化関数に与えてニューロンが発火するかどうかを判定しています。
活性化関数としてはシグモイドとReLUが代表的ですが、グラフにあるようにある閾値を越えるとyの値が増えるのがわかると思います。
活性化関数もライブラリで用意されてますので引数を渡して呼べばいいだけです。

では、重みデータの最適化はどのように行われるのでしょうか?
最初は、重みデータは0で初期化されていたりランダムな数値が設定されていたりします。
それを、教師データを読み込んで正解と予測値を比べて差異がなくなるまで繰り返し試行錯誤を行います。

f:id:anthony-g:20190927153013p:plain

上の図で損失関数というのが正解と予測値の差を求める関数で、オプティマイザーは差の値を元にニューラルネットの重みデータを更新します。
損失関数には二乗和誤差とか交差エントロピー誤差などがあり、オプティマイザーのアルゴリズムもRMSPropやAdamといったものがありますが、扱うケースによってライブラリのパラメータで指定することができますので内部の詳細なアルゴリズムまで知らなくても使うことができます。
(もちろん、興味のある方はぜひ勉強してみてください。)

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

ディープラーニングが一番脚光を浴びたのは画像認識です。
動物や人の顔を見分けたり地形を検知したりいろんなところで応用されています。
画像認識でよく使わるのが畳み込みニューラルネット(Convolutional Neural Net)と呼ばれるものです。

f:id:anthony-g:20190927155613p:plain

上図に畳み込み層とプーリング層というのがあると思いますが、これは画像の特徴あるところを抽出する層です。
詳細は本を読んでいただいたほうがいいと思いますが、例えば人が猫の写真を見た場合、顔の形とか目などの特徴を抽出して判断しているらしいのですがそれと似たことをCNNでも数値処理として行っています。
後、ソフトマックスというのは複数の値を出力するための層で、例えば猫である確率と犬である確率と人である確率を出したい場合は3つの出力を持つソフトマックスということになります。
そして、いまやディープラーニングは人間の認識能力を上回るようになりました。
人間でも気づかないような特徴をコンピューターが認識できるようになったということなのでしょうね。

RNN(リカレントニューラルネット

ただ、CNNには過去のデータを覚えられないという弱点があります。
例えば、文脈で判断する必要のある文章や過去の動作情報が必要な対物検知など時系列のデータを扱うものには使えません。
そこで考えられたのがリカレントニューラルネット(Recurrent Neural Net)です。

f:id:anthony-g:20190927160611p:plain

上図左のRNNが一つのニューラルネットを表していて、自分の出力を入力に再投入します。
右図は詳細の図で、前のニューラルネットの結果を次のニューラルネットに入力することによって前のデータの反映した出力を行うことができます。

かなりざっとした説明になってしまいましたが、ディープラーニングを学ぶ上でこれだけ前知識があれば本を読む時にかなり理解しやすいと思います。
特にご紹介した2冊は私が見た中では一番わかりやすいのでぜひ読んでみてください。
また、ネタが溜まってきたらブログでまとめたいと思います。

Elixirを使ってみたらとても楽しかった

Elixirはマルチプロセスを前提とした関数型プログラミング言語でエリクソンが電話交換機プログラムのために開発したErlangという仮想マシンシステム上で動作します。
Elixirが流行ってきた背景として、CPUが複数コアで構成されるようになり個人のパソコンでも8コアや16コアのCPUが使われるようになってきたのがあると思います。
しかし、CやJava,Pythonなどの現在主流の言語はシングルコアのCPUを前提にした言語なのでマルチコアをうまく扱えません。
そこでGoやRustなど新しい言語が登場してきたのですが、Elixirはその中でも比較的とっつきやすく関数型プログラミングのよさもうまく取り込んだ言語です。
ただ、古いタイプの言語に慣れている人にはそこがとっつきにくい部分かもしれません。

最新の情報を得たかったのでこちらの本で学びました。

Programming Elixir ? 1.6: Functional |> Concurrent |> Pragmatic |> Fun

Programming Elixir ? 1.6: Functional |> Concurrent |> Pragmatic |> Fun

Elixirを使ってみて私がいいなと思ったのはこんなところでした。

  • Lispっぽいリスト
  • mapや再帰を使ってループを使わない
  • 関数シグネチャーを使って条件分岐を行う
  • 関数を複数つなぐパイプオペレーター
  • 複数プロセス間のメッセージ通信が簡単

Lispっぽいリスト

昔、EmacsというエディタでLispという言語を使ったことがありますが、Elixirの配列はLispによく似てると思いました。
例えば、Lispはリスト構造が基本でcarやcdrというリストの先頭やそれ以外を取得する関数があります。
それと同じような機能がElixirにもあります。
例えば、配列の先頭を取得するには以下のように書きます。

iex > [ head | tail ] = [ 1 , 2 ,3 ,4 ,5 ]
iex > head
1
iex> tail
[ 2, 3, 4, 5 ]

ちなみにiexはElixirのシェルみたいなものでRubyでいうirbと同じものです。 この言語を作った人は明らかにLisperですね。

また、mapというデータタイプを使うことができます。

iex> map = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}
iex> map[:a]
1

mapとはキーと値がペアになっているデータで、他の言語では連想配列と呼ばれているものです。
ちなみに配列の添字に使われている:a や:bはアトムと呼ばれている定数データで見た感じ文字列のように見えますが スキャン処理などを高速に行えるようにハッシュ値のようなデータです。
Rubyのシンボルを同じですね。

再帰を使ってループを使わない

Lispでは再帰呼び出しというテクニックをよく使いますが、Elixirでもよく使われます。 再帰とは関数の中で自分自身を呼ぶことをいいます。
例えば、フィボナッチ数を計算する関数はこんな感じです。

def fib_calc(n) do
   result = fib_calc(n - 1) + fib_calc(n - 2)
end

フィボナッチ数は最初0と1から始まるので停止条件として書いておくべきなのですが上の例では省略しました。
CやJavaで書く場合はforループなどで集計していくことが多いですが、再帰で書くことによってシンプルな記述になるところがいいですね。
ただ、再帰は慣れていないと訳がわからないコードになりがちなのでプログラマーの習熟が必要です。
また、再帰は普通スタック領域をたくさん消費したり実行速度が遅かったりするのですが、Elixirではうまく最適化してくれているようです。

関数シグネチャーを使って条件分岐を行う

例えば、C言語でエラー処理のコードはこんな感じになります。

func1(int val , int error_code){
   if (error == 0){
          do_something(val);
   }else{
         do_error(error_code);
   }
}

Cでコード書いていると条件分岐でエラー処理だらけになることが多いです。
一方、Elixirではこういう書き方ができます。

defmodule m1 do
    def func1( {:ok, val}) do
           do_something(val)
    end
    def func1({:error, error_code}) do
            do_error(error_code)
     end
end

波括弧の引数はタプルと呼ばれているデータ型で変更できない配列です。
上の例では同じ名前で引数の違う関数func1が定義されます。
Elixirでは同じ関数名でも引数を変えることにより別の関数として定義することができます。
したがって、この例では:okを引数に与えると通常の処理をして:errorを与えるとエラー処理が行われます。
このように、Elixirではifなどの条件分岐をできるだけ使わないようにしてコードの見通しをよくすることができます。

関数を複数つなぐパイプオペレーター

シェルをご存知の方はコマンド同士をつなぐパイプという機能があるのをご存知だと思います。

# cat abc.txt|grep "ABC" | wc -l

Unixのコマンドは一つ一つは単純な処理しかできませんが、パイプで組み合わせることによって様々な処理を行わせることができます。
Elixirにもパイプオペレーターというものがあり、関数をつないで複雑な処理を行わせることができます。

iex> "Elixir rocks" |> String.upcase() |> String.split()
["ELIXIR", "ROCKS"]

上の例では|>がパイプオペレーターで"Elixir rocks"という文字列がString.upcase()関数の第一引数として与えられます。
つまり、String.upcase("Elixir rocks")を呼んでるのと同じことになります。
次のString.split()も同様にデータが流れます。
Unixエンジニアにはあたかもシェルスクリプトを書いているみたいでたまらない機能ですね。

大量プロセスを起動してもオーバーヘッドが少ない

Elixirでは簡単に複数のプロセスを立ち上げて並列で処理させることができます。
ここでいうプロセスとはOSネイティブのプロセスではなくElixirのVM上で実行するプロセスなのでとても軽いものになっています。
プロセスの生成は以下のように行います。

spawn(module_name, function_name, [function_params])

例えば、複数のプロセスで合計するプログラムはこんな感じになります。

defmodule ParalellSum do
    def psum(n) do
        result = Enum.reduce(n, fn(x, acc) -> x + acc end)
        result
    end
    def do_process(n) do
        num_processes = n
        calc_val = [1,2,3,4,5]
        Enum.each 1..num_processes, fn(_) -> spawn(ParalellSum, :psum, [calc_val]) end
    end
    def run(n) do
        :timer.tc(ParalellSum, :do_process, [n])
        |> IO.inspect
    end
end

大まかに説明すると、spawn(..)でプロセスを生成してpsum()という関数を別プロセスで並列に動かしています。
psum()関数はcalc_valの要素を合計します。
このプログラムをプロセス数1000,10000,100000で動かした結果がこちらです。

$ elixir -r myprocess.ex -e "ParalellSum.run(1000)"
{1756, :ok}
$ elixir -r myprocess.ex -e "ParalellSum.run(10000)"
{18173, :ok}
$ elixir -r myprocess.ex -e "ParalellSum.run(100000)"
{156408, :ok}

run関数のパラメータがプロセス数で結果の数値は実行時間をマイクロ秒で出力します。
ご覧の通り、10万プロセスで0.1秒ほどしかかかっていません。
ちなみに実行環境はMacBookPro Corei5 2.3GHzでした。
プロセスによるオーバーヘッドはほぼないと考えて開発できますね。

複数プロセス間のメッセージ通信が簡単

Elixirの一番の売りはプロセス間通信が簡単なことです。
次の例はエコーサーバーを生成してクライアントのメッセージをそのまま返すプログラムです。

defmodule Echo1 do
    def echo_back do
        receive do
            {sender, msg} ->
                send sender, {:ok, "#{msg}" }
        end
    end
end

# client
pid = spawn(Echo1, :echo_back, [])
send pid, {self(), "Hello World !"}

receive do
    {:ok, message} ->
        IO.puts message
end

spawn()関数でエコーサーバーを生成してクライアントから"Hello World!"というメッセージを送信するとサーバーがそのまま返します。
send pid,...がサーバーにメッセージを送信しているところで、echo_back関数のreceive do...のところで受信しています。
{send, msg}->のところは送られてきたメッセージのパターンを記述するところでマッチすればそれ以下の処理が実行されます。
したがって、このパターンを複数持たせればメッセージパターンによって違う処理をさせることができます。 LinuxC言語でデーモンを書くよりはるかに簡単ですね。

ざっと触ったところではこんな感じでした。
また、ElixirにはRailsに似たウェブフレームワークPhenixや組み込み系フレームワークのNervesなどがあっておもしろそうです。
Elixirはマルチプロセスで通信しながら処理を行うのが当たり前なのでRubyPythonとは違った作りにできると思います。
次回ウェブアプリ開発を行うときはElixirを使ってみたいなと思いました。

Vue.jsを使ってみてよかったところ、イマイチなところ

Vue.jsはReact,Angularに並ぶJavascriptフレームワークです。
しばらくフロントエンド開発にはかかわらなかったのでいろいろハマりましたが、備忘録も兼ねてまとめてみました。

Vue.jsのいいところ

リアクティブシステム

Vue.jsはリアクティブシステムになっています。
リアクティブシステムとは、ある変数の値を変更するとブラウザ上の表示も自動でアップデートしてくれるしくみをいいます。
例えば、以下のようなJavascriptのコードの場合、

let price = 1000;
let quantity = 10;

total = price*quantity;

totalに計算結果が出力されますが、後でpriceの値を変更(例えばprice = 200)にしてもtotalの値は変わりません。
しかし、リアクティブシステムではpriceの変更にともなってtotalが更新されます。
Vue.jsでは以下のように書きます。

var vm = new Vue({
   el: '#app',
   data: {
     price: 1000,
     quantity: 10
   },
   computed: {
    totalPrice(){
       return this.price * this.quantity
     }
  }
})

<div id="app">
  <div>Price: ${{ price }}</div>
  <div>Total: ${{ totalPrice}}</div>
</div>

ブラウザのデベロッパーツールのコンソールを開いて以上のコードを入力したあと、vm.price = 2000と入力するとTotalが自動で20000に更新されます。 これによりネイティブアプリのようなダイナミックなウェブアプリを作ることができます。
もしリアクティブでないJavascriptで同じようなことをやろうとすると、自分で変数の更新をチェックし変更されたらターゲットフィールドの値を更新するという処理を自分で書かなければいけません。
ダイナミックなウェブアプリを開発するときにとても便利ですね。

UIを部品化できる

Vue.jsは、コンポーネントと呼ばれるしくみによってソフトウェアを部品化して再利用できるようになっています。
例えば、ボタンの押した回数を表示する部品はこんな感じに書けます。

Vue.component('counter', {
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

コンポーネントをVue.jsで利用するためには以下のように書きます。

<div id="app">
  <counter></counter>
</div>
new Vue({ el: '#app' })

counterというタグでクリックすると数えてくれるパーツとして扱えます。

フレームワークがある幸せ

複数のメンバーでチームで開発する場合、フレームワークがあると規約に則って開発することができるのでメンバー間で話し合いながら作るときにはとても役に立ちます。
Vue.jsでは単一ファイルコンポーネントという形式があります。

<template>
  <p>{{ greeting }} World!</p>
</template>

<script>
module.exports ={
  data: functon(){
     return {
        greeting: 'Hello'
     }
 }
}
</script>

<style scoped>
p {
  font-size: 2em;
  test-align: center;
}
</style>

templateタグのところが表示するHTMLで、scriptタグがJavascriptコード、styleタグがCSSコードを記述するところです。
通常、それぞれのタグ部分はHTMLファイル、JSファイル、CSSファイルに分けて記述されますが、一緒に書けるようにすることでモジュール性を強化しています。

さらに、vue-cliを使えば自動的にディレクトリ、ファイルを生成して整えてくれます。
vue-cliパッケージをnpmでインストールしてプロジェクトの雛形を作成してみましょう。

# npm install vue-cli
# npm install -g @vue/cli
# vue create <ディレクトリ名>

vue createでは以下のようなファイルが作成されます。

f:id:anthony-g:20190430123205p:plain

Vue.jsプログラムファイルはsrcディレクトリ下にあり、以下のようなファイル構成になっています。

f:id:anthony-g:20190501154027p:plain

App.vueとmain.jsがプログラムメインファイルで、componentsディレクトリ以下のファイルがコンポーネントのプログラムファイルです。
このようにvue-cliでプロジェクトの雛形が作成されます。

Vue.jsのイマイチなところ

コンポーネント間のデータやりとりが面倒

コンポーネント構造になっていることによってプログラムの規模が大きくなってもプログラムがスパゲッティー化しないのでいいのですが、コンポーネント間で情報をやり取りする必要が出てきて結構面倒くさいです。
コンポーネント間のデータのやり取りは2つの方法があります。

1. propによるデータのやりとり
親のコンポーネントから子のコンポーネントへデータを渡すには子コンポーネントにpropsを定義します。

main.js

// 子コンポーネント
const childComponent = {
   props: ['myMessage'],
   template: '<span>{{ myMessage }}</span>
}

// 親コンポーネント
new Vue({
    el: '#app',
    components: {
         'childComponent': child-component
    }
});

html

...
<child-component v-bind:my-message="こんにちは"></child-component>
...

HTML上では属性名は大文字小文字を区別しないので、タグ名はchild-component、属性名はmy-messageという感じでキャメル形式をケバブ形式に変換しています。 しかし、propsを使う方法は親から子への一方向でしか情報をやりとりできません。
子から親に情報を伝えるためにはemitを使って可能です。 情報の伝達方向でやり方が違うというのもいまいちな感じです。

2. Vuexによるデータのやりとり
しかし、コンポーネント間の関係が親子関係であるとはかぎりません。
そういうときはVuexを使います。
Vuexとは、Vue.jsアプリケーションローカルに持つことのできるDBのようなデータ格納領域を作成するライブラリで、全てのコンポーネントからアクセスすることができます。
まず、Vuexのストアを定義します。
store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(vuex)

const store = new Vuex.Store({
  state: {
         myMessage: ""
  },
  mutations: {
   setMyMessage(state,{msg}){
      state.myMessage = msg
   }
})

stateに格納するデータを、myMessageと定義して文字列を持つようにします。 Vuexでデータを更新する場合は、commit()を呼ばなければいけないお約束になっていて、mutationsはその関数を定義するところです。 次に、main.jsでstoreをVue.jsに読み込みます。

src/main.js

...
import store from './store'
...
new Vue({
    render: h => h(App),
    store: store
}).$mount('#app')

次に、コンポーネントでstoreにアクセスしてみます。

src/components/xxx.vue

<template>
<div>
  <span>{this.$store.state</span>
   <input type="text" />
   <button @click="ok()">OK</button>
</div>
</template>
<script>
export default {
  name: "xxx",
  methods: {
     ok(){
         this.$store.commit('setMyMessage",{myMessage: "Hello World"})
     }
   }
}
</script>

これはテキストボックスに入力してボタンを押すとVuexの情報が更新される例です。 これでVuexを介してコンポーネント同士のデータのやり取りができるようになりますが結構面倒ですね。 Vuexについての詳しい解説は以下のURLを参照してください。

vuex.vuejs.org

リアクティブシステムがわかりにくい

リアクティブシステムはリッチなUIを作るには便利なのですが、どのタイミングで更新されるのかがわかりにくいというのがあります。
例えば以下の例の場合、

src/components/xxx.vue

<template>
<div v-if="showComponent">
...
</div
</template>
<script>
export default {
   name: "xxx",
   computed: {
      showComponent(){
         return this.$store.state.showFlag
      }
   }
}
</script>

VuexデータのshowFlagでコンポーネントを表示したり消したりしたいのですがうまく動きません。 (これで結構長い間悩みました。)
VuexストアのshowFlagが更新されたらshowComponentが呼ばれてほしいのですがそうはなりません。
v-ifのほうでリアクティブな変数をモニターしているみたいなのですが、computedメソッドの中までは見てないみたいです。
こういうところが最初とまどうところです。

学習コストがやや高め

通常プログラムは記述した順番に実行されるものですが、リアクティブシステムは何かを変更したらキックされるイベントドリブンなシステムなので慣れるまで少しかかります。
また、モジュール化でソースが複数ファイルに分かれてしまうので、なれないと全体が見えづらいというのもあります。

結論

ちょっと使った感じでは、Vue.jsは規模の大きなフロントエンド開発向けなのかなと感じました。
ただ、うまく動かないときに調べるのが結構大変だったのでデバッグがもう少しやりやすくなるといいと思いました。
Reactも少し触ってみましたが、なんでもかんでもJavascriptのコードにしてしまうReactよりVue.jsのほうがわかりやすい印象でした。
あと、VuexとVue-Routerはほぼ必須で使うコンポーネントだと思います。
最初は少しとっつきにくいですが、慣れれば使って損はないのではないでしょうか。

参照URL:
www.vuemastery.com