人工無脳をつくってみようとする6
文字単位N-gramモデルか、MeCabによる単語単位N-gramモデルかを選べるように。辞書データの保存は我流謎フォーマットから、StorableモジュールかData::Dumperモジュールで行なうように。あとはそーね、(2+i)-gramモデルに対応。1-gramモデルで統計を取るにはちょっとコード書き換えなきゃいけねー。
んで、それらの違いをパラメータの変更でできるように。
人工無脳としての機能改良はほぼ無し。っていうかまだ全く人工無脳エンジンとしてなりたってないし。
考えていることは、MeCabから品詞IDを貰ってほげほげすることと、会話中にぐぐって勝手に知識を増やすこと、トリガーモデルっぽいものを組み込むこと。あと会話らしくするための、相手の発言により生起確率をほげほげしてくれるモデルの搭載。っていうか、これが無いと無脳じゃねえ。
というわけで、まだまだ無脳には遠いMezassiエンジン。持ってるモデルはまだN-gramしか無いけどがんばれめざし、負けるなめざし。
# Chatbot "Mezassi" Engine package Mezassi; use strict; use warnings; use Storable qw(nstore retrieve); use Data::Dumper; $Data::Dumper::Indent=1; use MeCab; sub new{ my ($pkg) = @_; $conf = { dic_hash => {}, bos => ['&bos1;', '&bos2;', '&bos3;'], eos => '&eos;', unit => 'word', dic_type => 'store', }; bless $conf, $pkg; } BEGIN{ my $mecab = new MeCab::Tagger("-Owakati"); my $ascii = '[\x00-\x7F]'; my $twoBytes = '[\x8E\xA1-\xFE][\xA1-\xFE]'; my $threeBytes = '\x8F[\xA1-\xFE][\xA1-\xFE]'; sub unitsplit{ my ($self, $sentence) = @_; if($self->{'unit'} eq 'word'){ return split(" ", $mecab->parse($sentence)); } elsif($self->{'unit'} eq 'character'){ return $sentence =~ /$ascii|$twoBytes|$threeBytes/og; } } } sub add_chain{ my ($self, $next, @preunits) = @_; my $chain = $self->{'dic_hash'}; foreach(@preunits){ ++($chain->{sum}); $chain->{next}{$_}={} if(!defined($chain->{next}{$_})); $chain = $chain->{next}{$_}; } ++($chain->{"sum"}); ++($chain->{next}{$next}); } sub get_chain{ my $self = shift; my @preunits = @_; my $chain = $self->{'dic_hash'}; foreach(@preunits){ $chain = $chain->{next}{$_}; } return $chain; } sub read_dic{ my ($self, $dic_name) = @_; if($self->{'dic_type'} eq 'store'){ $self->{'dic_hash'} = retrieve($dic_name); } elsif($self->{'dic_type'} eq 'dump'){ $self->{'dic_hash'} = require $dic_name; } } sub write_dic{ my ($self, $dic_name) = @_; if($self->{'dic_type'} eq 'store'){ nstore($self->{'dic_hash'}, $dic_name); } elsif($self->{'dic_type'} eq 'dump'){ open(DIC, ">$dic_name"); print DIC Dumper($self->{'dic_hash'}); close(DIC); } } sub read_sentence{ my ($self, $sentence) = @_; my @preunits = @{$self->{'bos'}}; return if($sentence eq "\n"); chomp($sentence); my @unitlist = $self->unitsplit($sentence); foreach(@unitlist){ $_ = escape($_); $self->add_chain($_, @preunits); shift @preunits; push(@preunits, $_); } $self->add_chain($self->{'eos'}, @preunits); } sub gen_sentence{ my ($self) = @_; my @preunits = @{$self->{'bos'}}; my $sentence = ""; my $chain = $self->get_chain(@preunits); while(defined($chain)){ my @next_list = keys(%{$chain->{next}}); my $next_sum = $chain->{"sum"}; foreach(@next_list){ if(rand($next_sum) > $chain->{next}{$_}){ $next_sum -= $chain->{next}{$_}; next; } shift @preunits; push(@preunits, $_); last; } last if($preunits[@preunits-1] eq $self->{'eos'}); $sentence .= $preunits[@preunits-1]; $chain = $self->get_chain(@preunits); } return descape($sentence); } sub escape{ my ($unit) = @_; $unit =~ s/&/&/g; return $unit; } sub descape{ my ($unit) = @_; $unit =~ s/&/&/g; return $unit; } sub read_log{ my ($self, $log_name) = @_; open(LOG, $log_name)||die("cannot open $log_name\n"); while(<LOG>){ $self->read_sentence($_); } close(LOG); } sub write_log{ my ($self, $log_name, $sentence) = @_; open(LOG, ">>$log_name")||die("cannot open $log_name\n"); print LOG $sentence; close(LOG); } sub reset_dic{ my ($self) = @_; $self->{'dic_hash'} = {}; } 1;
コメントが無いなあ。設計がいきあたりばったりなもんで。脳味噌はいまだに行指向プログラミング。