1

Simple + dirty Python binding for Moses (SMT decoder)

I want to call Moses from python like below:

from moses import Moses
m = Moses("enth/model/moses.ini")
print m.decode("i eat rice")
# result: ฉัน กิน ข้าว

so i create this extension.

moses.cpp:
#include
#include “structmember.h”
#include “Parameter.h”
#include “StaticData.h”
#include “Manager.h”
#include “Hypothesis.h”
#include
#include
#include

typedef struct {
PyObject_HEAD
Parameter *param;
const StaticData *staticData;
vector *weights;
vector *inputFactorOrder, *outputFactorOrder;
FactorMask *inputFactorUsed;
long translation_id;
} Moses;

static int
Moses_traverse(Moses *self, visitproc visit, void *arg)
{
return 0;
}

static int
Moses_clear(Moses *self)
{
// FIXME
return 0;
}

static void
Moses_dealloc(Moses* self)
{
Moses_clear(self);
self->ob_type->tp_free((PyObject*)self);
}

static PyObject *
Moses_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Moses *self;

self = (Moses *)type->tp_alloc(type, 0);

if (self != NULL) {
self->param = new Parameter();
if(self->param == 0) {
Py_DECREF(self);
return NULL;
}
self->staticData = &(StaticData::Instance());
if(self->staticData== 0) {
Py_DECREF(self);
return NULL;
}

self->weights = new vector;
if(self->weights == 0) {
Py_DECREF(self);
return NULL;
}

self->inputFactorOrder = new vector();
if(self->inputFactorOrder == NULL) {
Py_DECREF(self);
return NULL;
}

self->outputFactorOrder = new vector();
if(self->outputFactorOrder == NULL) {
Py_DECREF(self);
return NULL;
}

self->inputFactorUsed = new FactorMask();
if(self->inputFactorUsed == NULL) {
Py_DECREF(self);
return NULL;
}

self->translation_id = 0;

return (PyObject *)self;
}

static int
Moses_init(Moses *self, PyObject *args, PyObject *kwds)
{
const char *ini_path;

if(!PyArg_ParseTuple(args, “s”, &ini_path))
return -1;
if(!(self->param->LoadParam(std::string(ini_path))))
return -1;

if (!StaticData::LoadDataStatic(self->param))
return -1;

if(self->weights) {
delete self->weights;
self->weights = new vector(self->staticData->GetAllWeights());
}

if(self->weights->size() != self->staticData->GetScoreIndexManager().GetTotalNumberOfScores())
return -1;

if(self->inputFactorOrder && self->outputFactorOrder && self->inputFactorUsed) {
delete self->inputFactorOrder;
delete self->outputFactorOrder;
delete self->inputFactorUsed;
self->inputFactorOrder = new vector(self->staticData->GetInputFactorOrder());
self->outputFactorOrder = new vector(self->staticData->GetOutputFactorOrder());
self->inputFactorUsed = new FactorMask(*self->inputFactorOrder);
}
return 0;
}

static PyMemberDef Moses_members[] = {
/*
{“first”, T_OBJECT_EX, offsetof(Moses, first), 0,
“first name”},
{“last”, T_OBJECT_EX, offsetof(Moses, last), 0,
“last name”},
{“number”, T_INT, offsetof(Moses, number), 0,
“moses number”}, */
{NULL} /* Sentinel */
};

static PyObject *
Moses_decode(Moses* self, PyObject *args)
{
const char *source_sentence;
if(!PyArg_ParseTuple(args, “s”, &source_sentence))
return NULL;
std::stringstream s;
s < < source_sentence <inputFactorOrder)) {
if (long x = source.GetTranslationId()) {
if (x >= self->translation_id) {
self->translation_id = x + 1;
}
} else {
source.SetTranslationId(self->translation_id++);
}
Manager manager(source, self->staticData->GetSearchAlgorithm());
manager.ProcessSentence();
const Hypothesis *hypo = manager.GetBestHypothesis();
PyObject* result = PyList_New(0);
while(hypo != NULL) {
stringstream phrase_stream;
phrase_stream < GetCurrTargetPhrase();
PyList_Append(result,
PyString_FromString(phrase_stream.str().c_str()));
hypo = hypo->GetPrevHypo();
}
PyList_Reverse(result);
return result;
} else {
PyErr_SetString(PyExc_RuntimeError, “Input cannot be read properly”);
return NULL;
}
}

static PyMethodDef Moses_methods[] = {
{“decode”, (PyCFunction)Moses_decode, METH_VARARGS,
“Return decoded target language”},
{NULL} /* Sentinel */
};

static PyTypeObject MosesType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
“moses.Moses”, /*tp_name*/
sizeof(Moses), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)Moses_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
“Moses objects”, /* tp_doc */
(traverseproc)Moses_traverse, /* tp_traverse */
(inquiry)Moses_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Moses_methods, /* tp_methods */
Moses_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Moses_init, /* tp_init */
0, /* tp_alloc */
Moses_new, /* tp_new */
};

static PyMethodDef module_methods[] = {
{NULL} /* Sentinel */
};

#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initmoses(void)
{
PyObject* m;

if (PyType_Ready(&MosesType) < 0)
return;

m = Py_InitModule3("moses", module_methods,
"Example module that creates an extension type.");

if (m == NULL)
return;

Py_INCREF(&MosesType);
PyModule_AddObject(m, "Moses", (PyObject *)&MosesType);
}

setup.py:
from distutils.core import setup, Extension

module1 = Extension('moses',
define_macros = [('MAJOR_VERSION', '0'),
('MINOR_VERSION', '1')],
include_dirs = ['../moses/src'],
libraries = ['moses', 'z', 'oolm', 'dstruct', 'misc'],
library_dirs = ['../moses/src'],
sources = ['moses.cpp'])

setup (name = 'moses',
version = '0.1',
description = 'This is a demo package',
author = 'Vee Satayamas',
author_email = 'vsatayamas@gmail.com',
url = 'http://www.python.org/doc/current/ext/building.html&#039;,
long_description = '''
This is really just a demo package.
''',
ext_modules = [module1])

0

xmlrpc ด้วย python บน apache

xmlrpc ด้วย python บน apache ผ่าน mod_wsgi. ใช้ xmlrpc บน python เขียนง่ายมากเลย ทั้ง client และ server ดูตัวอย่างจาก http://docs.python.org/library/simplexmlrpcserver.html ได้

แต่ว่า simple server นี้เป็น standalone server แล้วผมก็เจอปัญหาอีกว่า พอเรียกใช้จากเครื่องอื่น ที่ไม่ใช่เครื่องเดียวกันแล้วมั้นช้าๆ ชอบกล เลยเปลี่ยนไปใช้ wsgi-xmlrpc แทน มีคนเขียนไว้ให้แล้วด้วยดีจัง ^_^.

ทีแรกผมก็ลงโปรแกรมจาก easy_install เลย ใช้ easy_install wsgi_xmlrpc อะไรทำนองนี้ก็ลงได้ แต่เล่นไปเล่นมาเจอปัญหาภาษาไทย ก็เลยเอา source code จาก svn trunk ที่ google code มาใช้แทน ถึงตอนนี้ก็ยังใช้ได้ดีอยู่. (วิธีใช้ mod_wsgi กับ userdir เข้าไปดูที่ http://blog.vee-u.com/2008/06/18/mod_wsgi_userdir_ubuntu/ ได้
และ http://blog.vee-u.com/tag/wsgi/ ได้)

เพื่อที่ผมจะได้เอาไว้ดูเองในภายหลังด้วยจึงต้อง post ตัวอย่างสักหน่อย สมมุติ เขียน client แบบนี้

# -*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

from xmlrpclib import ServerProxy
server = ServerProxy("http://localhost/test_service.wsgi", encoding="UTF-8")
print server.test_func("ดีจ๊ะ")

พอโปรแกรมทำงานแล้วได้ผลแบบนี้

ดีจ๊ะ ^_^

เวลาเขียน server ก็เขียนประมาณนี้ใน test_service.wsgi

import site
import os

os.environ['PYTHON_EGG_CACHE'] = "/somewhere/egg"
site.addsitedir("/home/vee/pyenv/WSGI-1/lib/python2.5/site-packages")

from wsgiref import simple_server
import wsgi_xmlrpc

def test_func(txt):
   return txt + " ^_^"

application = wsgi_xmlrpc.WSGIXMLRPCApplication(methods=[test_func])

^_^

0

dicthttp แบบมี xml และระบุ dict server ได้

dicthttp เป็นโปรแกรมที่ครอบ dict protocol ไว้อีกทีเพื่อที่จะใช้งานผ่าน http ได้ จะได้ไม่โดน block และใช้กับเทคนิค ajax ได้ด้วย. จาก ความเดิมในตอนที่แล้ว. dicthttp ให้ผลลัพธ์ออกมาเป็นแบบ json แถมยังเลือกไม่ได้ว่าจะใช้ dict server ตัวไหน จาก comment ของ @bact และ @jittat ก็ทำให้ได้ url แบบนี้ออกมา

http://localhost:8000/d:แมว?host=dict.longdo.com&format=xml

มี host=dict.longdo.com และ format=xml เข้ามาเพื่อระบุ dict server และ format ตามลำดับนั้นเอง

dict

มีภาพประกอบด้วย :-P

โปรแกรมก็เหมือนเดิม checkout ออกมาจาก svn ได้เลย http://code.google.com/p/basaasa/source/browse/#svn/trunk/dicthttp.

0

เที่ยวรถ สุวรรณภูมิ – ระยอง

suwannabhumi - rayong bus schedule

ผมอยากลองขึ้นรถไปกลับระยองจากสุวรรณภูมิดูบ้าง แต่ก็ยังไม่ล้องเพราะว่าสนามบินโดนยึดไปเสียก่อน. ตอนนี้ได้สนามบินคืนมาแล้ว แต่ก็ไม่รู้ว่าทุกอย่างจะกลับมาเหมือนเดิมหรือยัง. คนที่เข้ามาเข้ายึดก็ลอยนวลออกไปเฉยๆ ต่อไปก็อาจจะกลับมายึดอีก.

ผมเลยยังไม่เคยลองใช้เส้นทางที่ว่าเลย. คิดเอาไว้ว่าต่อไปอาจจะขึ้นรถไฟฟ้าไปสุวรรณภูมิไป ตอนนี้ก็ขึ้นรถเมล์ไปก่อน.

0

Python 3.0 release

เข้าไปดูได้ที่ http://docs.python.org/dev/3.0/whatsnew/3.0.html. ผมยังไม่ได้ลองใช้เลย แต่อ่านดูก็เป็นรุ่นที่มีการเปลี่ยนแปลงใหญ่โตที่เดียว คำสั่ง print ต้องใส่วงเล็บ เช่น print(10) แทนที่จะเป็น print 10 แบบแต่ก่อน. ใช้ list น้อยลงไปใช้ view กับ iterator แทนในหลายกรณี เช่น คำสั่ง map ก็ return iterator ออกแทน แบบนี้น่าจะ ประหยัด memory ขึ้นมั้ง.  เรื่อง unicode, syntax และอื่นๆ อีกมากมาย อ่านได้ที่ http://docs.python.org/dev/3.0/whatsnew/3.0.html. ไม่รู้มีอะไรมาช่วย migrate code จาก Python 2.x หรือเปล่า?

ได้ข่าวผ่านมาทาง http://developers.slashdot.org/article.pl?sid=08%2F12%2F04%2F0420219&from=rss

update: มีตัวแปลง code เก่าให้ใช้กับ Python 3.0 ด้วย นอกจากนั้นก็มีข่าวภาษาไทยด้วยที่ blognone

update2: มี dictionary comprehension ด้วยคล้ายๆ list comprehension น่าใช้มากมาย ^_^

4

dict api over http

ผมอยากให้ basa-asa (ซึ่งเป็นโปรแกรมช่วยแปลภาษา เช่น ช่วยเปิด dictionary ให้ ไม่ใช่โปรแกรมแปลภาษาอัตโนมัติแบบ Google translation) เปิด dictionary ผ่าน dict protocol ได้ เพราะว่าจะได้สะดวกทั้ง dictionary ที่ download มาได้และ dictionary ของชาวบ้านที่เขาไม่ให้ download (ไม่รู้ว่าจริงๆ แล้วมีหรือเปล่า dictionary ที่ใช้ผ่าน dict protocol ได้แต่ไม่ให้ download).  แต่ว่า dict protocol นี้อาจจะเขียน javascript ไปเปิดตรงๆ ลำบากสักหน่อย มากไปกว่านั้น protocol ต่างๆ ที่ไม่ใช่ http ก็มักจะโดนปิดกั้นอย่างน่าเศร้าใจ. ด้วยเหตุผลดังกล่าวผมก็เลยทำ dicthttp ขึ้นมาเป็นตัวหุ้ม (wrapper) dict server ไว้อีกที แล้วก็แปลง ผลที่ได้เป็นแบบ json ส่งผ่าน web (http) ไป.

เวลาใช้ dict protocol เราอาจจะค้นหาคำโดยใช้ url แบบ dict://hostname/d:word:database อะไรทำนองนี้ เวลาทำ wrapper ผมก็ทำให้ใช้ประมาณนั้นคือ http://hostname/d:word:database ได้เหมือนกัน แล้วผลก็ return มาเป็น json. โดยเป็น list ของ {ชื่อ database, คำที่ใช้ค้นหา, definition}.

แบบนี้เป็นต้น

$ curl http://localhost:8000/d:computer:gcide
[{"word": "Computer", "def": "Computer \\Com*put\"er\\ (k[o^]m*p[=u]t\”[~e]r), n.\n1. One who computes.\n\n2. (Computers) an electronic device for performing\ncalculations automatically. It consists of a clock to\nprovide voltage pulses to synchronize the operations of\nthe devices within the computer, a central processing\nunit, where the arithmetical and logical operations are\nperformed on data, a random-access memory, where the\nprograms and data are stored for rapid access, devices to\ninput data and output results, and various other\nperipheral devices of widely varied function, as well as\ncircuitry to support the main operations.\n\nNote: This modern sense of computer comprises the\nstored-program computers, in which multiple steps in a\ncalculation may be stored within the computer itself as\n{instructions} in a {program}, and are then executed by\nthe computer without further intervention of the\noperator. Different types of computer are variously\ncalled {analog computer}, {number cruncher,\nnumber-cruncher}, {digital computer}, and {pari-mutuel\nmachine, totalizer, totaliser, totalizator,\ntotalisator}.\n\nSyn: data processor, electronic computer, information\nprocessing system.\n[WordNet 1.5 +PJC]\n\n3. (Computers) same as {digital computer}.\n[PJC]“, “database”: “gcide”}, {“word”: “computer”, “def”: “electronic device \\electronic device\\ n.\na device depending on the principles of electronics and using\nthe manipulation of electron flow for its operation.\n[PJC]\n\nNote: Numerous electronic devices are in daily use, among\nthem the {television}, {radio}, {computer}, {robot},\n{transmitter}, {receiver}, {VCR}, {CD player}, etc.\n[PJC]“, “database”: “gcide”}]

ขยุกขยุยไปบ้าง … แต่มันก็เป็นแบบนี้ล่ะ

นอกจากคำสั่ง define ใน dict protocol แล้วก็ใช้ match ได้ด้วย แบบ http://hostname/m:คำ:database:strategy ได้ด้วย. แต่เหมือน n ยังใส่ไม่ได้ หาไม่เจอว่าจะใส่ตรงไหนของ dictclient (python).

โปรแกรม dicthttp อยู่ที่ http://code.google.com/p/basaasa/source/browse/#svn/trunk/dicthttp ใช้ wsgi พื้นๆ