【機械学習/ディープラーニング】G検定合格のためにやったこと

f:id:mofmof721:20190716141434j:plain
この度、JDLA G検定2019#2に無事合格しました。
勉強開始からの3か月間にやったことを、よかったもの悪かったもの含めて書いていきます。

Aidemy

会社からAidemyのe-learningを受講して、その成果を確認するためにG検定を受験するよう指示されたので、まずAidemyから着手しました。
結論として、G検定対策としてAidemyをやるのは違う、と思いました。

AidemyはPython機械学習モデルを実装できるようになることを目標にしていますが、
G検定にはプログラミングスキルは求められません。
Aidemyが悪いわけではなく、Aidemyの狙いとG検定の狙いはあまり一致していないというだけです。

2019年6月頭にAidemyにもG検定対策コースが追加されましたが、動画で解説を見たあと、演習問題を解くという構成になっています。
動画だと復習したい内容をすぐに探せないので、別の勉強方法で勉強した方が効率的だと思います。

Aidemyの使い方としては、G検定対策で機械学習の基礎的な知識を身につけたあと、実装ができるようになるために使うのが正しい使い方だと思います。

Aidemyは1か月ちょっとでさくっと終わらせて、残りの約2か月ではAidemyはほとんど使わず、独自でG検定対策を進めました。

人工知能は人間を超えるか

こちらは入門書として読むのに最適でした。
人工知能の歴史や、G検定対策のために重要なキーワードを理解するのに役立ちます。
読みやすく、理解しやすい内容になっているので、さくっと読めます。
ただし、出版から数年が経過し、記述が古くなっている部分もあります。

G検定問題集(黒本)

徹底攻略 ディープラーニングG検定 ジェネラリスト問題集

徹底攻略 ディープラーニングG検定 ジェネラリスト問題集

上記の本を読んだあと、こちらの問題集(通称:黒本)に着手しました。
JDLAの公式テキスト(通称:白本)は買ってません。Amazonのレビューが微妙だったので…。
白本と黒本両方使って勉強されている方が多いようですが、黒本だけでも合格できました。
あまりお金をかけたくない場合は、こちらの問題集だけでもいいと思います。(受験費用もかかるし、AI白書も高い!)

解説がわかりやすいので、基礎的な知識を身につけるのに非常に役立ちます。
私はこの問題集をメインに勉強し、もっと詳しく知りたいと思った部分についてはネットで調べて勉強しました。

本番の試験でも、この本の問題がそのまま出題されたものがいくつかありました。
G検定対策にはマストの一冊です。

5月中旬頃からこの問題集を使って勉強し、5月末頃には巻末の模擬問題の正解率が98%になるまで勉強しました。
この問題集をきちんとこなせるようになることがG検定合格の必要条件だと思います。ただし十分条件ではない。

Study-AI

study-ai.com
黒本を終わらせたあと、こちらの模擬問題をやりました。
全く調べずにこの模擬問題を解くとかなり難しいですが、できなくても気にする必要はないです。
本番の雰囲気をつかむことと、時間の使い方を練習するために使うといいです。

AI白書

AI白書 2019

AI白書 2019

過去に受験された方のブログを読むと「AI白書からの出題が多い」と書かれていたので購入しました。
紙の本はでかくて重いので、Kindle版を購入。
6月頭頃から読み始めましたが、結果読み切れてません…。

幅広い内容を網羅するため、解説が少なくなっています。
きちんと理解するためにぐぐりながら読んでいると時間が足りず…。
試験が近くなってから時間が足りなくなり、6月後半は出題されそうなところをさらっと目を通すだけで終わってしまいました。

法律関連の問題が多く出題されたので、その部分はしっかり読んでおいた方がいいです。
ただし、この分厚い本の内容を全部覚えるのは現実的ではないです。
大まかに内容を把握して、どこにどんな内容が書いてあったか覚えておいて、試験本番のときに調べるのに使うのがいいかと思います。
私はWindows版のKindleアプリをインストールしておいて、本番中に本文の検索ができるようにしておきました。

試験本番の解き方

まず、確実に解ける問題を素早く解くようにしました。
わからない問題、自信がない問題は印を付けておいて、どんどん先に進めるようにしました。
残り時間を40分くらい残した状態で最終問題まで終わったので、残りの時間は印をつけた問題を調べながら解きました。
G検定は問題数が多いので、調べる時間をどれだけ残せるかが勝負になります。

読んでよかった本

G検定対策に直接かかわるわけではないですが、読んでよかった本を紹介します。

Aidemyをやっていて、テキストの内容が全然理解できないことに危機感を抱いて購入しました。
巻末には高校数学の解説も載っているので、数学が絶望的に苦手な私でも読めました。

この本で解説されているのは勾配降下法とロジスティック回帰の二つだけになります。
どちらも機械学習の超基本的な内容なので、読んで損はないです。

反省

色々失敗もしましたが、G検定合格のためにやるべきは以下だと思います。
優先度が高い順に書きます。

・「人工知能は人間を超えるか」を読む
・黒本の問題を解く
・Study-AIの模擬問題を解く
・「AI白書」を読む

成績優秀者を目指すわけでなければ、これだけやっておけば大丈夫だと思います。
G検定合格はゴールではなく、機械学習の入り口に立っただけなので、引き続き頑張りたいです。

【Play Framework 2.4】Eclipseでデバッグする

f:id:mofmof721:20151227114038p:plain:w200
Play Framework技術メモ第三回。
今回はEclipseデバッグする方法について。
公式のドキュメントはこちら
https://www.playframework.com/documentation/2.4.x/IDE

目次

デバッグモードで起動する

今までPlayアプリケーションを起動するにはactivator runコマンドを使用していました。
このコマンドを使用すると、本番モードでサーバーが起動します。

デバッグモードで起動するには、activator -jvm-debug 9999 runコマンドを使用します。
また、~runコマンドを使用すると、ソースを修正すると自動で再コンパイルしてくれます。
これはsbtのTriggered executionという機能を使用していて、ファイルが更新されると再度アクションが実行されるようになっています。
sbtの公式ドキュメントはこちら
http://www.scala-sbt.org/0.13/docs/Howto-Triggered.html

手作業でサーバーを再起動させる手間がなくなるので、開発中は~runを使うのをおすすめします。
デバッグモードで自動コンパイルをオンにして起動するコマンドは以下になります。

activator -jvm-debug 9999 ~run

Eclipseデバッグの構成を行う

Eclipseでプロジェクトを右クリック→デバッグデバッグの構成を選択します。
f:id:mofmof721:20151231002654p:plain

リモートJavaアプリケーション上で右クリック→新規を選択します。
f:id:mofmof721:20151231002730p:plain

ポートを9999に変更し、適用をクリックしたあと、デバッグをクリックします。
f:id:mofmof721:20151231002750p:plain

あとはブレークポイントを張ると、通常のJavaアプリケーションと同様にデバッグできます。
デバッグを終了するときは「切断」をクリックします。
デバッグを開始したあとにソースを変更すると「同期がとれていない可能性があります」と表示されることがあります。
一度切断したあと再度デバッグを開始すると正常に実行できます。
f:id:mofmof721:20151231003311p:plain

【Play Framework 2.4】Ebeanを使った検索処理

f:id:mofmof721:20151227114038p:plain:w200
Play Framework 2.4技術メモ第二回。
今回はDB接続について。
公式のドキュメントはこちら
https://www.playframework.com/documentation/2.4.x/SettingsJDBC


目次

DB情報

DBはMySQLを使います。DBの設定は先に済ませておいてください。
今回は以下の設定でDBを作成しました。

データベース名:play_test
ユーザー名:play_test
パスワード:play_test

設定ファイルの編集

application.confの設定

(プロジェクトのディレクトリ)→conf→application.confを開きます。
30行目付近からDBの設定が書いてある箇所があるので、コメントアウトを外し、自分の環境に合わせて記述を書き換えます。

# Database configuration
# ~~~~~
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
#
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/play_test?characterEncoding=UTF8"
db.default.username=play_test
db.default.password="play_test"

イコール以下を自分の環境に合わせて設定します。

40行目付近にEvolutionsの設定があります。
Evolutionsはddlの作成・実行を自動で行う機能です。
最初の状態はplay.evolutions.enabled=falseコメントアウトされていて、Evolutionsを使用する設定になっています。

今回はコメントアウトを外してEvolutionsを使わないよう設定します。
Evoluthinsを使う場合はコメントアウトしたままでOKです。

# Evolutions
# ~~~~~
# You can disable evolutions if needed
play.evolutions.enabled=false

一番下の行に、以下の一文を追加します。

ebean.default = ["models.*"]

application.confの全文はこうなります。

# This is the main configuration file for the application.
# ~~~~~

# Secret key
# ~~~~~
# The secret key is used to secure cryptographics functions.
#
# This must be changed for production, but we recommend not changing it in this file.
#
# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
play.crypto.secret = "changeme"

# The application languages
# ~~~~~
play.i18n.langs = [ "en" ]

# Router
# ~~~~~
# Define the Router object to use for this application.
# This router will be looked up first when the application is starting up,
# so make sure this is the entry point.
# Furthermore, it's assumed your route file is named properly.
# So for an application router like `my.application.Router`,
# you may need to define a router file `conf/my.application.routes`.
# Default to Routes in the root package (and conf/routes)
# play.http.router = my.application.Routes

# Database configuration
# ~~~~~
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
#
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/play_test?characterEncoding=UTF8"
db.default.username=play_test
db.default.password="play_test"

# Evolutions
# ~~~~~
# You can disable evolutions if needed
play.evolutions.enabled=false

# You can disable evolutions for a specific datasource if necessary
# play.evolutions.db.default.enabled=false

ebean.default = ["models.*"]

build.sbtの設定

(プロジェクトのディレクトリ)→build.sbtを開きます。
sbtはライブラリの管理などを行うビルドツールです。
build.sbtに設定を追加して、必要なライブラリをダウンロードするよう設定します。

5行目あたりにlazy val root = (project in file(".")).enablePlugins(PlayJava)の記述があるので、
enablePluginsのかっこの中に,PlayEbeanを追加します。

lazy val root = (project in file(".")).enablePlugins(PlayJava,PlayEbean)

9行目付近からlibraryDependencies ++= Seq(…)の記述があるので、Seqのかっこ内に必要なライブラリを記述します。
今回はevolutionsとMySQL Connectorを追加します。

libraryDependencies ++= Seq(
  evolutions,
  javaJdbc,
  cache,
  javaWs,
  "mysql" % "mysql-connector-java" % "5.1.20"
)

build.sbt全文はこうなります。

name := """play-test"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayJava,PlayEbean)

scalaVersion := "2.11.6"

libraryDependencies ++= Seq(
  evolutions,
  javaJdbc,
  cache,
  javaWs,
  "mysql" % "mysql-connector-java" % "5.1.20"
)

// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator

これで設定が完了したので、検索処理を実装します。

検索処理を実装する

Ebeanとは

今回はEbeanを使ってDB操作を行います。

Ebeanは、Javaのためのオブジェクト関係マッピング (ORM)ライブラリである。JPA (Java Persistence API) やJDO (Java Data Objects) よりもシンプルに使えて、かつ理解しやすいように設計されている。
Ebean - Wikipedia

Play Frameworkについて解説した記事ではEbeanを使っていることが多いので、こちらでもEbeanを使います。

作成したテーブル

今回は以下のSQLでユーザーマスタを作成しました。

CREATE TABLE `user_master` (
  `user_id` char(64) NOT NULL,
  `user_name` varchar(100) NOT NULL,
  `password` varchar(64) NOT NULL,
  `regist_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

このテーブルに合わせてエンティティクラスを実装します。

エンティティクラスの作成

(プロジェクトのディレクトリ)→app内にmodelsパッケージを作成します。
以後、このパッケージ内にエンティティクラスを作成します。
今回はUserMasterクラスを作成しました。
f:id:mofmof721:20151227205317p:plain

エンティティクラスではcom.avaje.ebean.Modelクラスを継承します。

package models;

import com.avaje.ebean.Model;

/**
 * ユーザーマスタエンティティクラス
 *
 */
public class UserMaster extends Model {

}

Play 2.3までではplay.db.ebean.Modelクラスを使用していましたが、
Play 2.4からplay.db.ebean.Modelクラスが非推奨になり、com.avaje.ebean.Modelクラスに変更されました。

エンティティクラスの中身を実装します。
各カラム用の変数をメンバ変数で作ります。

package models;

import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import com.avaje.ebean.Model;
import com.avaje.ebean.annotation.CreatedTimestamp;
import com.avaje.ebean.annotation.UpdatedTimestamp;

/**
 * ユーザーマスタエンティティクラス
 *
 */
@Entity
@Table(name = "user_master")
public class UserMaster extends Model {

	/**
	 * ユーザーID
	 */
	@Id
	@Column(name = "user_id")
	private String userId;

	/**
	 * ユーザー名
	 */
	@Column(name = "user_name")
	private String userName;

	/**
	 * パスワード
	 */
	@Column(name = "password")
	private String password;

	/**
	 * 登録日時
	 */
	@CreatedTimestamp
	@Column(name = "regist_time")
	private Timestamp registTime;

	/**
	 * 更新日時
	 */
	@UpdatedTimestamp
	@Column(name = "update_time")
	private Timestamp updateTime;

	/**
	 * find
	 */
	private static Find<Long, UserMaster> find = new Find<Long, UserMaster>() {
	};

	/**
	 * ユーザーID取得
	 *
	 * @return ユーザーID
	 */
	public String getUserId() {
		return userId;
	}

	/**
	 * ユーザーID設定
	 *
	 * @param userId
	 *            ユーザーID
	 */
	public void setUserId(String userId) {
		this.userId = userId;
	}

	/**
	 * ユーザー名取得
	 *
	 * @return ユーザー名
	 */
	public String getUserName() {
		return userName;
	}

	/**
	 * ユーザー名設定
	 *
	 * @param userName
	 *            ユーザー名
	 */
	public void setUserName(String userName) {
		this.userName = userName;
	}

	/**
	 * パスワード取得
	 *
	 * @return パスワード
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * パスワード設定
	 *
	 * @param password
	 *            パスワード
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * 登録日時取得
	 *
	 * @return 登録日時
	 */
	public Timestamp getRegistTime() {
		return registTime;
	}

	/**
	 * 登録日時設定
	 *
	 * @param registTime
	 *            登録日時
	 */
	public void setRegistTime(Timestamp registTime) {
		this.registTime = registTime;
	}

	/**
	 * 更新日時取得
	 *
	 * @return 更新日時
	 */
	public Timestamp getUpdateTime() {
		return updateTime;
	}

	/**
	 * 更新日時設定
	 *
	 * @param updateTime
	 *            更新日時
	 */
	public void setUpdateTime(Timestamp updateTime) {
		this.updateTime = updateTime;
	}

	/**
	 * find取得
	 *
	 * @return find
	 */
	public static Find<Long, UserMaster> getFind() {
		return find;
	}

	/**
	 * find設定
	 *
	 * @param find
	 *            find
	 */
	public static void setFind(Find<Long, UserMaster> find) {
		UserMaster.find = find;
	}
}

各種アノテーションを使い、テーブル名やカラム名などを設定しています。

@Entity

エンティティクラスであることを示すアノテーション

@Table

name = ○○でテーブルの物理名を設定しています。

@Id

そのカラムが単独PKであることを示すアノテーション

@Column

name = ○○でカラムの物理名を設定しています。

@CreatedTimestamp

登録日時を示すアノテーション
このアノテーションを設定すると、登録処理を行ったときに自動で処理日時が設定されます。

@UpdatedTimestamp

更新日時を示すアノテーション
このアノテーションを設定すると、更新処理を行ったときに自動で更新日時が設定されます。

Find

FindクラスはSELECT文を生成するクラスです。
Play 2.3まででは検索処理にplay.db.ebean.Model.Finderクラスを使用していましたが、2.4ではplay.db.ebean.Modelクラスが非推奨になり、
代わりにPlay 2.4からcom.avaje.ebean.Model.Findクラスを使用するようになっています。

検索を実行する

(プロジェクトのディレクトリ)→controllersにApplicationクラスがあります。
今回はこの中に検索処理を実装します。

package controllers;

import play.mvc.Controller;
import play.mvc.Result;

import views.html.index;

public class Application extends Controller {

	public Result index() {
		// ここに検索処理を実装する

		return ok(index.render("Your new application is ready."));
	}

}

returnの前にユーザーマスタを全件検索し、取得したデータの利用者名をコンソールに出力する処理を書きました。

package controllers;

import java.util.List;

import models.UserMaster;
import play.mvc.Controller;
import play.mvc.Result;

import views.html.index;

/**
 * コントローラークラス
 *
 */
public class Application extends Controller {

	/**
	 * index画面アクセス時処理
	 *
	 * @return 処理結果
	 */
	public Result index() {
		// ユーザーマスタを検索する
		List<UserMaster> userMasterList = UserMaster.getFind().all();
		for (UserMaster data : userMasterList) {
			// 利用者名を出力する
			System.out.println(data.getUserName());
		}
		// index画面を表示する
		return ok(index.render("Your new application is ready."));
	}

}

全件検索を行う場合はcom.avaje.ebean.Model.Find.all()メソッドを使用します。

検索結果を確認する

テーブルには以下のデータを登録してあります。

user_id user_name password regist_time update_time
0000000001 田中 太郎 tanaka 2015/12/27 20:36:56 2015/12/27 20:36:56
0000000002 山田 一郎 yamada 2015/12/27 20:36:56 2015/12/27 20:36:56


サーバーを起動し、localhost:9000にアクセスします。
登録したユーザー名がコンソールに表示されているので、検索結果の出力が成功していることが確認できます。
f:id:mofmof721:20151227214105p:plain

参考

MySQLのDB接続設定はこちらの記事を参考にしました。
qiita.com

Ebeanの使い方はこちらを参考にしました。
mpon.hatenablog.com

【Play Framework 2.4】Play Framework導入手順

f:id:mofmof721:20151227114038p:plain:w200
最近まで仕事でPlay Framework 2.4を使って開発を行っていましたが、日本語の情報が少ない! 公式のドキュメントも日本語版は2.3までしか出てない!
そのため、このブログに情報を残すことにしました。

今回はPlay Frameworkの導入手順についてです。
PlayではJavaScalaのいずれかを選択しますが、今回はJavaを使います。
公式のインストール手順解説ページはこちら
https://www.playframework.com/documentation/2.4.x/Installing

目次

jdkのインストール

まず、jdkをインストールし、パスを通します。
手順はこの記事を参照。
PATHの設定及び環境変数JAVA_HOMEの設定 - Javaダウンロードとインストール

この手順に加えて、Pathに

%JAVA_HOME%\bin\;
を追加します。

Play Frameworkのダウンロード

Play Frameworkの公式ページからtypesafe-activatorをダウンロードします。
ダウンロードページはこちら
https://www.playframework.com/download
今回はPlay 2.4.3のactivatorをダウンロードしました。

ダウンロードしたファイルを解凍し、パスを通します。
Pathには解凍したファイルのactivator.batがあるフォルダのパスを指定します。
f:id:mofmof721:20151227122936p:plain
今回はD:\play\activator-1.3.7-minimalに解凍したので、環境変数Pathに

D:\play\activator-1.3.7-minimal;
を追加します。

Play Frameworkのインストール

Pathを通したら、コマンドプロンプトでactivator.batがあるディレクトリに移動し、

activator help
コマンドを実行します。このコマンドが実行できたらパスが通っているのでOKです。

新規プロジェクト作成

新規Playプロジェクトを作成します。
コマンドプロンプトでPlayプロジェクトを作成するディレクトリに移動します。
今回はD:\repo内にプロジェクトを作成したいので、cd D:\repoを実行します。

ディレクトリを移動したら、プロジェクトを作成するコマンドを実行します。
今回は「Play-test」というプロジェクト名で作成するので、

activator new play-test play-java
を実行します。自分の作成するプロジェクトに合わせて「play-test」の箇所を書き換えてください。
「play-java」で、使用する言語を指定しています。Scalaを使用する場合は「play-scala」に書き換えてください。

Playアプリケーションの起動

プロジェクトの作成が完了したら、Play Frameworkを起動させて確認します。

まず、作成したプロジェクトのディレクトリに移動します。
今回はD:\repo\play-testにプロジェクトを作成したので、cd D:\repo\play-testを実行します。

プロジェクトのディレクトリに移動したら、Playアプリケーションを起動させます。

activator run
コマンドでサーバを起動させます。初回はコンパイルに時間がかかるので辛抱。
コマンドラインに「Server started,(以下略)」が出たらlocalhost:9000にアクセスします。
ここで「Welcome to Play」の画面が表示されたら成功です。
このあと設定ファイルを編集するので、ctrl + Dを押してサーバを停止させます。

Eclipseにプロジェクトをインポート

ここから2.4で変更された部分です。
Play Framework 2.4から、Eclipseで開発するにはプラグインを導入するよう変更されました。
公式の解説ページはこちら
https://www.playframework.com/documentation/2.4.x/IDE

プロジェクトのディレクトリ→project→plugins.sbtを開き、最後の行に以下の一文を追加します。

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")

コマンドプロンプトでプロジェクトのディレクトリに移動し、以下のコマンドを実行します。

activator eclipse
成功すると、プロジェクトのフォルダ内に「.project」ファイルが作成されます。

Eclipseを起動し、ファイル→インポート→一般→既存プロジェクトをワークスペースへを選択します。
f:id:mofmof721:20151227001414p:plain
プロジェクトを作成したディレクトリを指定し、完了を押します。
f:id:mofmof721:20151227125105p:plain

プロジェクトをインポートしたら、ビルドパスを修正します。
プロジェクト・エクスプローラーでPlayプロジェクトを選択して右クリック→ビルド・パス→ビルド・パスの構成を開きます。
「ソース」タブを開き、フォルダーの追加を選択します。
f:id:mofmof721:20151230170528p:plain
(プロジェクト)→target→scala-2.11→classesにチェックを入れてOKを押します。
f:id:mofmof721:20151230161905p:plain

viewのコンパイルエラーが消えない場合

ビルドパスを修正してリフレッシュした後でも、controllerでviewを呼び出している箇所のコンパイルエラーが消えない場合があります。
f:id:mofmof721:20151230193553p:plain

コンパイルエラーが消えない場合、まずbuild.sbtに以下のコードを追加します。

EclipseKeys.projectFlavor := EclipseProjectFlavor.Java           // Java project. Don't expect Scala IDE
EclipseKeys.createSrc := EclipseCreateSrc.ValueSet(EclipseCreateSrc.ManagedClasses, EclipseCreateSrc.ManagedResources)  // Use .class files instead of generated .scala files for views and routes 
EclipseKeys.preTasks := Seq(compile in Compile)                  // Compile the project before generating Eclipse files, so that .class files for views and routes are present

次に、インポートしたプロジェクトをEclipse上から削除します。
(ディスク上からプロジェクト・コンテンツを削除のチェックは入れないこと!)

Eclipseを終了し、

  1. activator clean
  2. activator update
  3. activator compile
  4. activator eclipse

の順にコマンドを実行します。
それが完了したら、上記の手順で再度Eclipseにプロジェクトをインポートします。
ビルドパスを修正してリフレッシュしたあと、コンパイルエラーが消えたら完了です。

参考

Play Framework 2.3についてはこちらのブログが詳しいです。
mpon.hatenablog.com

コンパイルエラーの解消方法はこちらを参考にしました。
stackoverflow.com


少し古いので2.4では使えない記述がありますが、全体的にわかりやすい技術本。