typescriptのビルド設定
はじめに
babel7がリリースされましたね!
それに伴いtypescriptもサポートされたのでbabel単体でtsのビルドができるようになりました。
しかしbabelはtypescriptから型情報を取り除くだけなので型チェックまではサポートしておらず、
型チェックに関してはtsc経由で行う必要あります。
今回はwebpack + babel + tsc + tslintでtypescriptのビルド+lint+型チェックを行えるようにしたいと思います。
※ソースはこちらです https://github.com/tmzkysk/hello_typescript
必要なmoduleをインストール
まずは適当に作業ディレクトリを作り、 npm(yarn) initでプロジェクトを作成してください。 ※yarnを入れていない人は随時npmで置き換えてください。
$ mkdir hello_typescript && cd hello_typescript $ yarn init
package.jsonが作成されたら必要なmoduleをインストールしていきます。
$ yarn add typescript webpack webpack-cli webpack-dev-server
$ yarn add -D @babel/core @babel/preset-env babel-loader ts-loader tslint tslint-loader prettier tslint-config-prettier tslint-config-standard tslint-plugin-prettier
ひとつずつ解説すると、
- webpack:言わずもがな。ファイルバンドリングツール。
- webpack-cli: webpackをcli上で使用できるようにする。
- webpack-dev-server:開発時にtsの変更をwatchして自動的にビルドする
- @babel/core:ES6 -> ES5を行うトランスパイラ
- @babel/preset-env:サポートされている環境に基づいて必要なBabelプラグインを自動で決定するライブラリ
- babel-loader:webpack上でbabelを使用するために必要
- ts-loader:webpack上でtypescriptのビルドをするのに必要
- tslint:typescriptの構文チェッカー(型チェックはやらないよ)
- prettier:コードフォーマッター
- tslint-config-prettier:TSLintの設定のうちPrettierと衝突するものを無効化してくれるパッケージ
- tslint-plugin-prettier:TSLintのチェックをかけるときに一緒にPrettierをながしてくれる
- tslint-config-standard:こちらの内容にそってTSLintのチェックをするときに必要
- tslint-loader:webpackでTSLintを使用するのに必要
結構多い。。。 TSLintとprettierの違いはこちらの記事が参考になります。 https://qiita.com/soarflat/items/06377f3b96964964a65d
typescript側の設定
tsconfig.jsonの作成
typescriptのビルドやチェックのルールを設定するファイルです。 以下のコマンドでディレクトリに作成されます。
$ yarn tsc --init
tsconfig.jsonの設定
configに設定できる項目はたくさんありますが、とりあえずこれらを設定しておけば良いと思います。 型チェックや不要な変数のチェックなどはtsconfig側の設定になります。
{ "compilerOptions": { /* Basic Options */ "target": "ESNEXT", /* tsを書くときにどのversionのESが対象か: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ "module": "ESNext", /* どのversionのESを生成するか: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "jsx": "preserve", /* reactを書くときに必要, 'react-native', or 'react'. */ // "outFile": "./", /* 出力するファイル(ファイル出力はwebpackで行うので不要) */ // "outDir": "./", /* 出力するディレクトリ(ファイル出力はwebpackで行うので不要) */ // "rootDir": "./", /* ビルド時のルートディレクトリ(ビルド対象のパス設定はwebpackで行うので不要) */ // "noEmit": "true", /* ビルド時に型ファイルを生成しない(これがあるとts-loaderでエラーが出るので外しています */ /* Strict Type-Checking Options */ "strict": true, /* すべての strict タイプ・オプション(noImplicitAny, strictNullChecks, noImplicitThis(thisの型チェック), alwaysStrict(strictモードのjs出力)) を 有効化する */ "noImplicitAny": true, /* any型の使用不可 */ "strictNullChecks": true, /* nullable型以外でnullを許容しない */ /* Additional Checks */ "noUnusedLocals": true, /* 未使用の変数を許容しない */ "noUnusedParameters": true, /* 未使用の変数を許容しない */ "noImplicitReturns": true, /* メソッド内で返り値の型があっているかをチェック */ /* Module Resolution Options */ "moduleResolution": "node", /* http://js.studio-kingdom.com/typescript/handbook/module_resolution 参照 */ "esModuleInterop": true /* ESModuleと同じ動作をする. */ } }
babelの設定
まずは.babelrcを作成します。
$ touch .babelrc
中身はこのような感じです。
(react開発をする場合は@babel/preset-react
が必要です)
{ "presets": [ "@babel/preset-env" ] }
tslintの設定
まずは設定ファイルを作ります。
$ touch tslint.json
中身はこのような感じ。
(reactの文法もチェックする場合はtslint-react
が必要です)
{ "rulesDirectory": [ "tslint-plugin-prettier" ], "extends": [ "tslint-config-standard", "tslint-config-prettier" ], "rules": { "prettier": [ true, { "singleQuote": true, // 文字列はシングルクオートで囲む "semi": false // 文末のセミコロン(;)は省く。prettierのデフォルトはtrue } ] } }
webpackの設定
まずは以下のコマンドでファイルを作成します。
$ touch webpack.config.js
module.exports = { mode: process.env.NODE_ENV || "development", entry: "./src/index.ts", output: { filename: "bundle.js", path: __dirname + "/dist" }, resolve: { extensions: [".ts", ".tsx", ".js", ".json"] }, module: { rules: [ { test: /\.ts?$/, use: [ // 下から順に処理される { loader: "babel-loader" }, { loader: "ts-loader" }, { loader: 'tslint-loader', options: { typeCheck: true, // tslint時に自動的に修正しない fix: false, // warningをエラーにすることでその後のビルドを止める emitErrors: true }, }, ], exclude: /node_modules/ } ] }, };
今回はsrc/index.ts
をビルドし、dist/bundle.js
として出力する前提で記載しています。
複数ファイルの場合は配列やhashでの設定も可能です。
注意する点としてはloaderは下から上の順に実行されるので、
1.tslint-loaderでlintチェック 2.ts-loaderでtypescript -> ES6へ変換 3.babel-loaderでES6 -> ES5へ変換
というようになっています。
ビルド用のtypescriptファイル準備
試しにビルドする用のtypescriptを用意しましょう。
今回はsrc/index.ts
を用意し、dist/bundle.js
として出力したいので準備をします。
$ mkdir src dist $ touch src/index.ts
中身は適当なtypescriptにしましょう。
const hoge: string = 'test' console.log(hoge)
package.jsonへscript設定
あとはこれらを実行するのですが、package.jsonのscript項目に記載しておけば、 npm(yarn) run [タスク名] で実行可能です。
{ "name": "hello_typescript", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "typescript": "^3.1.1", "webpack": "^4.20.2", "webpack-dev-server": "^3.1.9" }, "scripts": { "build": "webpack", "watch": "webpack-dev-server", "lint" : "yarn run tsc && yarn run tslint", "tslint": "tslint --project tsconfig.json" "tslint-fix": "tslint --fix --project tsconfig.json" }, "devDependencies": { "@babel/core": "^7.1.2", "@babel/preset-env": "^7.1.0", "babel-loader": "^8.0.4", "prettier": "^1.14.3", "ts-loader": "^5.2.1", "tslint": "^5.11.0", "tslint-config-prettier": "^1.15.0", "tslint-config-standard": "^8.0.1", "tslint-loader": "^3.6.0", "tslint-plugin-prettier": "^2.0.0", "webpack-cli": "^3.1.2" } }
実行
ようやくビルドできるようになりました。 実行してみましょう。
普通にビルド
$ yarn run build yarn run v1.5.1 $ webpack Hash: 8732ceeed4c190294712 Version: webpack 4.20.2 Time: 7067ms Built at: 2018-10-05 22:46:29 Asset Size Chunks Chunk Names bundle.js 3.84 KiB main [emitted] main Entrypoint main = bundle.js [./src/index.ts] 52 bytes {main} [built] ✨ Done in 8.76s.
できました! dist/bundle.jsが出来上がっていると思います。
lintは動くか
では、src/index.tsを以下のように書き換えてビルドするとどうなるか・・
const hoge: string="test"; console.log(hoge)
$ yarn run build yarn run v1.5.1 $ webpack Hash: 8f442c0fec1e406e6b3d Version: webpack 4.20.2 Time: 3450ms Built at: 2018-10-05 22:52:04 Asset Size Chunks Chunk Names bundle.js 3.85 KiB main [emitted] main Entrypoint main = bundle.js [./src/index.ts] 52 bytes {main} [built] [1 error] ERROR in ./src/index.ts Module Error (from ./node_modules/tslint-loader/index.js): [1, 19]: Replace `="test";` with `·=·'test'` error An unexpected error occurred: "Command failed. Exit code: 2 Command: sh Arguments: -c webpack Directory: /Users/tmzkysk/hello_typescript Output: ".
ちゃんとエラーになりました。
こういうときはyarn run tslint-fix
とすれば直ります。
$ yarn run tslint-fix yarn run v1.5.1 $ tslint --fix --project tsconfig.json Fixed 1 error(s) in /Users/tmzkysk/hello_typescript/src/index.ts
中身を見るとしっかり直ってます。 なお、webpack.config.jsのtslint-loaderのoptionのfixをtrueにすればビルド時に勝手に直してくれます。
$ cat src/index.ts const hoge: string = 'test' console.log(hoge)
型チェックとかはどうか
次にtypescriptのコンパイラ側のチェックがちゃんと動くか確認します。 index.tsを以下のようにしてビルドしてみます。
const hoge: number ="test" console.log(hoge)
$ yarn run build yarn run v1.5.1 $ webpack Hash: 8732ceeed4c190294712 Version: webpack 4.20.2 Time: 3322ms Built at: 2018-10-05 22:58:50 Asset Size Chunks Chunk Names bundle.js 3.84 KiB main [emitted] main Entrypoint main = bundle.js [./src/index.ts] 52 bytes {main} [built] [1 error] ERROR in /Users/tmzkysk/hello_typescript/src/index.ts ./src/index.ts [tsl] ERROR in /Users/hello_typescript/src/index.ts(1,7) TS2322: Type '"test"' is not assignable to type 'number'. error An unexpected error occurred: "Command failed. Exit code: 2 Command: sh Arguments: -c webpack Directory: /Users/tmzkysk/hello_typescript
number型にstring型を代入しているためしっかりエラーになりました。
その他
package.jsonに設定した以下の内容について解説します。
"scripts": { "build": "webpack", "watch": "webpack-dev-server", "lint" : "yarn run tsc && yarn run tslint", "tslint": "tslint --project tsconfig.json" "tslint-fix": "tslint --fix --project tsconfig.json" },
- build: webpack.config.jsの設定に沿ってビルドします。
- watch: webpack.config.jsの設定に沿ってビルドします。ファイルの変更を監視するのでtsファイル変更時に再度ビルドする必要がありません。
- lint: typescript側のビルド時のチェックとTSLintのチェックをかけます。
- tslint: TSLintのチェックのみかけます。
- tslint-fix: TSLintのエラーを修正してくれます。
webpack-dev-serverについて
基本的に開発時はファイル変更と同時にビルドが走って欲しいので、
webpack-dev-serverを使用することになります。
webpack-dev-serverはwebpack-cliと違い、
何も設定していなければ localhost:8080
にビルド後のassetを吐き出すので、
railsでwebpackでビルドしたassetを参照する場合はlocalhost:8080
から読み込むようにしてください。
おわりに
@babel/preset-typescritp
がtsconfigの内容を踏襲してくれれば楽でしたが、
現状型チェックは提供されていないのでts-loaderをかませるようにしています。
今後のbabelに期待!
golangテストはじめ
はじめに
golangでのテストはとてもシンプルで、rubyのrspecのように新しくDSLを覚える必要もありません。
テストについての記事は沢山あるのですが、自分の中で特にこれは最初に覚えておいた方がいいなと思うことをピックアップしました。
基本的なtestの書き方
- 例えばcalc.go のテストならば同じディレクトリ内に
calc_test.go
という名前で作成する。 - テストファイル内では
testing
パッケージをインポートする。 - テストファイル内では、
TestXXX
という名前でテストメソッドを作成する。 - DSLは特に無いので普通にテストコードを書く。
- パラメータと期待値の組み合わせの配列を用意して、ループで検証していく形が推奨されている(Table Driven Test)
package calc func Add(a,b int) int { return a + b }
package calc import ( "testing" ) func TestAdd(t *testing.T) { patterns := []struct { a int b int expected int }{ {1, 2, 3}, {10, -2, 8}, {-10, -2, -12}, } for idx, pattern := range patterns { actual := Add(pattern.a, pattern.b) if pattern.expected != actual { t.Errorf("pattern %d: want %d, actual %d", idx, pattern.expected, actual) } } }
testの実行方法
- カレントディレクトリ以下すべてを再帰的にテスト
go test -v ./...
- 特定のパッケージをテスト
go test -v ./hogehoge
(パッケージディレクトリを相対パスで指定する) - 特定のメソッドのみテストする
go test -run TestAdd ./...
※ -v オプションを付けると実行結果に詳細が付きますので、基本的にはつけておいたほうが良いです。
テストの実行前後に処理を入れるには
TestMainメソッドを定義します。
code := m.Run()
を実行するとテストメソッドが走るので、その前後にDBの初期化処理等を入れることが出来ます。
package calc import ( "fmt" "os" "testing" ) func TestMain(m *testing.M) { fmt.Println("before test") code := m.Run() fmt.Println("after test") os.Exit(code) } func TestAdd(t *testing.T) { // 以下省略 }
これを実行すると、以下のようになります。
テストの前後にfmt.Printlnが入っているのがわかります。
$ go test -v ./... before test === RUN TestAdd --- PASS: TestAdd (0.00s) PASS after test ok
テストでモックを使うには
インターフェースを使ったモック
インターフェースを使っているオブジェクトの場合、実際のコードとテストコードでインタフェースに定義するオブジェクトを変えることでテスト時の振る舞いを変えることが出来ます。 ここではsomefuncパッケージのClientオブジェクトのRunメソッド内で呼び出されるcallメソッドの振る舞いを、モックを使って切り替える方法を紹介します。
package somefunc type Caller interface { call(val int) int } type Client struct { FuncCaller Caller } type ExampleCaller struct{} func (c *Client) Run(val int) int { return c.FuncCaller.call(val) } func (f *ExampleCaller) call(val int) int { return val }
上記のコードを実行するには以下のように呼び出します。
c := somefunc.Client{&somefunc.ExampleCaller{}}
c.Run(1)
ここで、テスト時にExampleCallerのモックを作って、callメソッドの振る舞いを変えるにはテストコードを以下のようにします。
package somefunc import ( "testing" ) func TestRun(t *testing.T) { patterns := []struct { val int expected int }{ {2, 2}, {8, 8}, {-10, -10}, } for idx, pattern := range patterns { // Clientのnewの際に、モックオブジェクトを引数にする c := Client{&mockCaller{}} actual := c.Run(pattern.val) if pattern.expected != actual { t.Errorf("pattern %d: want %d, actual %d", idx, pattern.expected, actual) } } } // callメソッドのレシーバをmockCallerとして宣言する。 type mockCaller struct{} // 通常のコードではcallメソッドは引数の値をそのまま返却するが、 // モックでは、引数 + 10した値を返却するようにする。 func (s *mockCaller) call(val int) int { return val + 10 }
変数の再代入で行う方法
ここではsomeprocessパッケージのRun関数のテストを行っていますが、Run内でcallという関数を呼び出しています。
このcall関数の挙動をテストの時だけ切り替えるには、call関数を変数に入れ、テスト内で変数にモックを再代入すればOKです。
package someprocess func Run(val int) int { return call(val) } var call = func(val int) int { return val }
package someprocess import ( "testing" ) func TestRun(t *testing.T) { call = func(val int) int { return val + 10 } patterns := []struct { val int expected int }{ {2, 12}, {8, 18}, {-10, 0}, } for idx, pattern := range patterns { actual := Run(pattern.val) if pattern.expected != actual { t.Errorf("pattern %d: want %d, actual %d", idx, pattern.expected, actual) } } }
anyenvを使って~env系をひとまとめにする
ruby, pythonを使用しているとrbenv, pyenv等を使ってバージョン管理をするが、
これらのバージョン管理システムは、言語ごとに導入、PATHを通す必要がある。
anyenvを使用すれば、これらの言語ごとのバージョン管理システムを一元管理できる。
1.以前使用していた~env系を削除
念の為。以前使用していた~env系とanyenvが競合しないように削除しておく。
brewでインストールしている場合は以下のコマンドでOK.
$ brew uninstall rbenv
他のツールが依存していると削除できないこともあるので、
その時はenvに依存しているツールを先に削除することでenvも削除することができる。
ディレクトリは残るのでこれも削除しておく。
$ rm -rf ~/.rbenv
2.anyenvのインストール
githubからcloneしてくる
$ git clone https://github.com/riywo/anyenv ~/.anyenv
PATHを通す。(bash_profileに記載)
if [ -d ${HOME}/.anyenv ] ; then export PATH="$HOME/.anyenv/bin:$PATH" eval "$(anyenv init -)" fi
おそらくanyenv導入前は、各env毎に↑のコードを書いていたと思う。
3.各種envをインストール
以下のコマンドで各envを導入する。
$ source ~/.bash_profile $ anyenv install rbenv $ anyenv install pyenv
あとは以前と同じように各言語のversionをインストールすればOK。
$ rbenv install 2.4.0
gitで歴史を改ざんするには
直前の履歴を改ざんする
1. コミットをなかったことに
HEADの一つ前に戻る。
$ git reset HEAD~1 $ git push -f origin
2. コミットを修正
対象ファイルを修正し、commit --amendする。
$ git commit --amend $ git push -f origin
特定の歴史を改ざんする
rebase -iを使い、改ざんしたいコミットまで戻り、修正する。
$ git rebase -i <改ざんしたいコミットのID> pick c832e Add comment pick f983e Initial commit
戻りたいコミットを指定し、editにし保存する。
edit c832e Add comment pick f983e Initial commit
改ざんしたいファイルを修正し、commit --amendする。 その後、git rebase --continueで元に戻す。
$ git rebase --continue
途中、コンフリクトが発生することがあるので、そのときは解消して、
rebase --continue
する。
Successfully rebased and updated refs/heads/ブランチ名
と出れば完了。
途中で訳わからなくなってもとに戻したいと思ったら↓のコマンドでOK。
$ git rebase --abort
n-gramによる文章の類似率を求める
N-gramとは、テキストで隣り合ったN文字のことを示す。
以下では2つ文章を指定された文字数で分割し、2つの文章間で分割した文字がどれだけマッチするかの頻度から、2つの文章の類似率を求める。
def ngram(str, num): res = [] slen = len(str) - num + 1 for i in range(slen): extract_str = str[i:i+num] res.append(extract_str) return res # 2つの文章の類似率を調べる def diff_ngram(str1, str2, num): str1_ngram = ngram(str1, num) str2_ngram = ngram(str2, num) match_result = [] count = 0 for str1_unit in str1_ngram: for str2_unit in str2_ngram: if str1_unit == str2_unit: count += 1 match_result.append(str1_unit) return count / len(str1_ngram), match_result # 2つの文章がどれだけ似ているかテストする # 文字の分割を2文字ごと3文字ごとにして調べる。 a = '今日、渋谷で美味しいトンカツを食べた。' b = '渋谷で食べた今日のトンカツは美味しかった。' result2, word_list2 = diff_ngram(a, b, 2) result3, word_list3 = diff_ngram(a, b, 3) print('2-gram:', result2, word_list2) print('3-gram:', result3, word_list3) # 2-gram: 0.6111111111111112 ['今日', '渋谷', '谷で', '美味', '味し', 'トン', 'ンカ', 'カツ', '食べ', 'べた', 'た。'] # 3-gram: 0.29411764705882354 ['渋谷で', '美味し', 'トンカ', 'ンカツ', '食べた']
これだと単純な接続詞とかでもヒットしてしまうのであまり精度は高く無い気がする。 もっと本格的に文章解析するならば、RNNやLSTMに手をつかけるのがいいのかな。。。
TensorflowとKerasを用いてmnistのCNNを構築してみる
コードは以下の通り。
Tensorflow・Kerasを使ってmnistの訓練を行う
from keras.models import Sequential from keras.datasets import mnist from keras.layers.convolutional import Conv2D from keras.layers.pooling import MaxPooling2D from keras.layers.core import Dense, Dropout, Activation, Flatten from keras.optimizers import Adam from keras.utils import np_utils from keras import backend as K # ------------------------------ # データ準備 # ------------------------------ (X_train, y_train), (X_test, y_test) = mnist.load_data() # データをfloat型にして正規化する X_train = X_train.astype('float32') / 255.0 X_test = X_test.astype('float') / 255.0 img_rows = 28 img_cols = 28 # image_data_formatによって畳み込みに使用する入力データのサイズが違う if K.image_data_format() == 'channels_first': X_train = X_train.reshape(-1, 1, img_rows, img_cols) X_test = X_test.reshape(-1, 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: X_train = X_train.reshape(-1, img_rows, img_cols, 1) X_test = X_test.reshape(-1, img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # ラベルはone-hot encodingを施す y_train = y_train.astype('int32') y_test = y_test.astype('int32') y_train = np_utils.to_categorical(y_train, 10) y_test = np_utils.to_categorical(y_test, 10) # ------------------------------ # モデルの定義 # ------------------------------ # 場合分けでインプットデータのテンソルの形を変える # mnistデータは28×28ピクセルで60000個のデータで、28×28ピクセルで1チャネルのデータに変える # reshapeの-1は、28×28ピクセルで60000個のデータを28×28ピクセルで1チャネルによしなに変えてくれる model = Sequential() # 畳み込み層1 # フィルタは5×5ピクセルで28個→出力データは32チャネル # 入力データは28×28ピクセルの1チャンネル # input_shapeを指定するのは1層目だけ model.add(Conv2D(32, (5, 5), input_shape=input_shape)) model.add(Activation('relu')) # プーリング層1 model.add(MaxPooling2D(pool_size=(2, 2))) # 畳み込み層2 # フィルタは5×5ピクセルで64個→出力データは64チャネル model.add(Conv2D(64, (5, 5))) model.add(Activation('relu')) # プーリング層2 model.add(MaxPooling2D(pool_size=(2, 2))) # Flattenして全結合する model.add(Flatten()) model.add(Dense(128)) model.add(Activation('relu')) # 過学習予防のためドロップアウトして最後に出力(出力データ数はone-hotなので10個) model.add(Dropout(0.5)) model.add(Dense(10, activation='softmax')) # ------------------------------ # 学習の開始 # ------------------------------ epochs = 20 batch_size = 100 adam = Adam(lr=1e-4) model.compile(optimizer=adam, loss='categorical_crossentropy', metrics=["accuracy"]) history = model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_split=0.1) loss, accuracy = model.evaluate(X_test, y_test, verbose=1) print('loss=', loss) print('accuracy=', accuracy)
以下、注意点。
- mnistは28×28の1チャネルだが、RGBの画像とかだと3チャネルになる。
- Conv2Dの引数は出力サイズ(フィルタのデータ数), フィルタの縦横サイズ、入力データのサイズ
- KerasのConv2Dでは、1層目のみ入力データのサイズの指定が必要
- KerasのバックエンジンによってConv2Dに渡す入力データのサイズの指定形式が異なる。
3つめの入力形式に関しては~/.keras/keras.json
に記載されているimage_data_formatをみて判断する。
コードでは、1層目でmnistのデータを(データの個数, 28ピクセル, 28ピクセル , 1チャネル)のテンソルに変換し、
(5ピクセル, 5ピクセル, 1チャネル)のデータ32個のフィルタにかけていて、その結果をプーリングして次の層へ渡す。
最終的な出力の前に全結合してドロップアウトした結果をソフトマックス関数にかけてone-hotのラベル形式で出力している。
TensorflowとKerasを使ってmnistの訓練と評価をしてみる
Tensorflow・Kerasとは(ザックリ)
インストール方法
とりあえずpipで入れてみる。
$ pip install -U tensorflow $ pip install -U keras
Tensorflow・Kerasを使ってmnistの訓練を行う
from keras.datasets import mnist from keras.models import Sequential from keras.layers.core import Dense, Dropout, Activation from keras.optimizers import Adam from keras.utils import np_utils # mnistデータの読み込み (X_train, y_train), (X_test, y_test) = mnist.load_data() # データをfloat型にして正規化する # データ数×縦ピクセル数×横ピクセル数のデータをデータ数×784の方にする X_train = X_train.reshape(60000, 784).astype('float32') / 255 X_test = X_test.reshape(10000, 784).astype('float') / 255 # ラベルをone_hot形式に変換 y_train = np_utils.to_categorical(y_train, 10) y_test = np_utils.to_categorical(y_test, 10) # モデルの構造を定義 model = Sequential() # 1層目 model.add(Dense(512, input_shape=(784,))) model.add(Activation('relu')) # 2層目 model.add(Dense(512)) model.add(Activation('relu')) # 出力 model.add(Dense(10)) model.add(Dropout(0.2)) model.add(Activation('softmax')) # モデルの構築 model.compile( loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy']) # データで訓練 hist = model.fit(X_train, y_train) # テストデータで評価する loss, accuracy = model.evaluate(X_test, y_test, verbose=1) print('loss=', loss) print('accuracy=', accuracy)
特に注目したいのがmodelを用いて直感的に学習の手順を記述することができる。
コードでは3層のニューラルネットワークを構築している。
Denseは全結合を行うモジュールで、1層目のみ入力データのサイズを指定する必要がある。
モデルを定義し、コンパイルし、訓練をし、テストデータで精度を評価するという流れ。