KerasでLSTMを使ってテスト駆動開発してみた
tl;dr
Kerasという機械学習のフレームワークのサンプルにあるLSTMを使い、テストコードを生成して、それをもとにテスト駆動開発してみた。
Kerasを試してみる
以前、紹介記事を書いたのでそちらを参照していただけると幸いです。
また、MLPを使った文の分類については以下の記事をご参照ください。
ソースコードを生成してみる
Kerasのexamplesに含まれているlstm_text_generation.py
を使って、文を生成してみることにチャレンジしてみたいと思います。ここではLSTMという構造が使われていますが、LSTMについては別の記事で少し紹介したので、そちらとその参考ページを参照いただけたら幸いです。
さて、元のコードではニーチェの文書をそのLSTMに学習させています。CPUマシンで計算させるとそれなりにまともな文章が出力されるまでとんでもなく時間がかかるのですが、例えば17イテレータでこんな文章が出力されました。
----- diversity: 1.0 ----- Generating with seed: "on as religion, art and ethics are so un" on as religion, art and ethics are so untorjuse of the nationar is the greater and repalsife man who law, it was supposed at the inplanatine, sole--of the whole poom befole this chacal we have sight of the are the divine patter. of the bits in the end, and the good and despriating the otherse, consequem and gratprouble autional enemat.--and a thing world agaits this difficeetis: the must is the greater of to the morality. one who are in
何のこっちゃといった感じですが、これは"on as religion, art and ethics are so un"をシード、つまりこの文字列から始まる文として、その続きをLSTMに予測させたものです。ご覧の通りそんなに精度よく文が生成されるわけではないのですが、今回はここにRuby on Rails5のソースコードのうち、テストコードだけを読ませてみたいと思います。
$ git clone https://github.com/rails/rails.git $ cd rails $ more `find . | grep _test.rb` > all_test.rb
これだけ抽出するだけでも5MBぐらいになり、5MB程度でも非力なCPUマシンでは1イテレータに10時間ほどかかってしまう見込みが出たので、split
コマンドを使って1MBずつに切り分けて、そのなかで最初のファイルを入力として指定してみます。さて、ちゃんとテストコードらしいコードを出力してくれるのでしょうか。結果はこのようなものがみてとれました。
----- diversity: 0.5 (9イテレータ目) def test_create_with_conditions_should_be_shared_with_conditions_on_conditions_on_many_and_limit_with_logs_target_with_propore_the_save comment = comment.projects.first assert_equal 1, post.all.merge!(:includes => :posts.id).post assert_equal 2, post.tags.belongs.size end def test_attribute_mattring_table_name_uniqueness_with_can_be_should_return_name column = companies(:f ----- diversity: 1.0 (9イテレータ目) equal startup, sponsor.sponsorable end test 'string withdenv = write ci nect('restraction is instance_destroying peoples- ta/se body face def test_precision_sql_from_select_view(*arging using attributet") do connection.project_id = forkal assert_equal 'w, sole assert posts(@connection.insert_line_it(with_serialize, default_end) assert_equal 0, parent.id \wifhoun data s iv� ssopeltriv" end ----- diversity: 0.5 (16イテレータ目) car = car.create!(bulbs: [first_name]) assert_equal 0, account.where("name = ?', ['author'], :interest.first_name: 'sting' end end def test_bould_name_prefixed_association_loading_with_belongs_to_and_on_association assert_equal 1, account.where("credit_limit = 10").to_a assert_equal 1, companies(:first_firm).clients_of_firm.reload.size end def test_no_collection_using_primary_key with_example_t
中には駄目そうなのもあり、diversityが高いほど駄目になっていますが、diversity=0.5で見た目では実行できそうなコードをピックアップすることができました。関数名がスネークケースで単語マシマシみたいになっていて英語的には破綻していますが、それでもちゃんとRubyで実行できそうなコードになっているのがわかります。
それではテスト駆動開発ということで、このテストに通りそうなコードを書いてみたいと思います。上のコードで、小文字と大文字を今回同一視しているのでその部分だけを修正してテストコードを作り、それをパスできるコードを書きます。
require 'test/unit' require "active_record" ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ':memory:' ) class InitialSchema < ActiveRecord::Migration def self.up create_table :comments do |t| t.string :name t.integer :project_id end create_table :projects do |t| t.string :name t.integer :comment_id end create_table :posts do |t| t.string :name end end end InitialSchema.migrate(:up) class ActiveRecord::Relation def post 1 end end class Symbol def id self.__id__ end end class Comment < ActiveRecord::Base has_many :projects end class Project < ActiveRecord::Base belongs_to :comment end class Post < ActiveRecord::Base def self.tags Tag.all end end class Tag < ActiveRecord::Base def self.belongs [0,1] end end class TestSample < Test::Unit::TestCase def setup @comment = Comment.new end def test_create_with_conditions_should_be_shared_with_conditions_on_conditions_on_many_and_limit_with_logs_target_with_propore_the_save comment = @comment.projects.first assert_equal 1, Post.all.merge!(:includes => :posts.id).post assert_equal 2, Post.tags.belongs.size end end
では、これを実行してみます。
$ ruby test_spec.rb
Loaded suite test_spec Started . Finished in 0.009579296 seconds. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 104.39 tests/s, 208.78 assertions/s
テストに通ったので、うまくいったといえそうです。
近い将来、人工知能がまだプログラムは組めないけれど、仕様書からテストコードぐらいは生成できるようになった過渡期が訪れたとき、我々人類はこのようにして、機械によって生成されたテストコードをパスするためのプログラムを書くだけの存在になってしまうかもしれませんね。