人工無脳をつくってみようとする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;コメントが無いなあ。設計がいきあたりばったりなもんで。脳味噌はいまだに行指向プログラミング。