最近实习公司做的项目要使用到Google Cloud上有关Machine Learning的API接口,所以最近一直看这方面的资料比较多,在这里整理一下简单的使用方法,免得之后自己走弯路。
公司需求
公司想做的是在一张图片中找到一串电表号(Numero de Compteur Electrique),并且提取中间的一部分。在之前的版本中都是用正则来做的,这一回试图用Google Cloud上的人工智能 API 进行尝试。尽管本人感觉熟悉之后用起来应该不是特别困难,但是感觉老板不是特别重视,让我尝试一下也只是看看前景。
主要用到的是:Google Cloud Vision API 和 Google Natural Language API
想要详细了解的话,肯定是去看google docs最方便,但是其中有些beta版的只支持英文,这里附上链接:Google AI Docs
Google Cloud Vision
Google Cloud Vision主要是为了把图片中的text转出来,使用的是ocr的接口。Github上有相当成熟的例子:OCR。主要流程就是,把图片上传到Cloud Storage之后,触发调用包含了OCR接口的Cloud Fonction,把处理之后的.txt在存回Cloud Storage里面。在Github上的例子里,Cloud Fonction还是包含其他API的,比如Translation API等,真正的大项目可能会触及费用问题。 部署函数时,需要用到:
gcloud functions deploy NAME --runtime RUNTIME
其中NAME必须和export的文件名保持一致,RUNTIME是运行环境(比如Python2.7)。
Google Natural Language
如果完全按照了上面的流程的话,OCR最终输出是在一个Cloud文件夹中的.txt文件。接下来用Natural Language做的就是在这些.txt文件中找到有用的数据。现有的Google IA 可以自主训练的AutoML中大多都是贴标签,但是Natural Language中的实物提取貌似可以抓住对应标签的对象,所以我就进行了尝试。
为了建立自己的模型,我先导出了一大批OCR的结果,自己写出了每个里的关键词。然后把他们逐个合并成立一群.jsonl文件。这里提及一下,训练自己的模型的使用流程是,先处理自己的数据使它变成.jsonl文件格式,之后上传云端的Cloud Storage,在之后制作一个.csv文件,用来把.jsonl文件们倒入Natural Language 的dataset。有点坑的是,跟着Google docs做的话很容易看着导入数据格式的文件,不小心把数据导入到Google Table里。这里要说的是Google docs有很棒的能帮忙把.txt文件转.jsonl文件并且自行生成.csv的脚本:Python Script这样做了之后,你需要在网站上自己添加Key和标签。
Jsonl文件的格式为:
{
"annotations": [
{
"text_extraction": {
"text_segment": {
"end_offset": number, "start_offset": number
}
},
"display_name": string
},
{
"text_extraction": {
"text_segment": {
"end_offset": number, "start_offset": number
}
},
"display_name": string
},
...
],
"text_snippet":
{"content": string}
}
我有两个.txt文件,一个每一行是text,另一个每一行是标签对应的Key。我的办法是自己先在本地添加好标签在上传(只有一个标签),附上代码:
const fs = require('fs');
const readline = require('readline');
readFileToArr("./catchinformation.txt", function (data) {
for (var i = 0; i < 88; i++) {
var index = fs.readFileSync("./Image/F" + (i + 1) + ".txt", 'utf-8');
var object = {
annotations: [],
text_snippet:
{ content: index }
};
if (data[i] != "") {
var annotation = {
text_extraction: {
text_segment: {
end_offset: index.search(data[i]) + data[i].length, start_offset: index.search(data[i])
}
},
display_name: "n_Matricule"
}
object.annotations.push(annotation);
}
var resultJson = JSON.stringify(object);
fs.writeFile("./Jsonl/F" + (i + 1) + ".jsonl", resultJson, 'utf8', function (err) {
if (err) {
console.log("An error occured while writing JSON Object to File.");
return console.log(err);
}
//console.log("JSON file" + (i + 1) + " has been saved.");
});
}
}
)
function readFileToArr(fReadName, callback) {
var fRead = fs.createReadStream(fReadName);
var objReadline = readline.createInterface({
input: fRead
});
var arr = new Array();
objReadline.on('line', function (line) {
arr.push(line);
//console.log('line:'+ line);
});
objReadline.on('close', function () {
// console.log(arr);
callback(arr);
});
}
//readFileToArr函数来源:https://blog.csdn.net/yajie_china/article/details/79407851
在这之后,导入一个格式如下的.csv文件用来生成dataset,你可以在这里自行定义自己的训练集和测试集,也可以不定义,那么Google将以 Train : Validate : Test = 8 : 1 : 1 进行随机分配。
TRAIN,gs://my-project-lcm/training-data/traindata.jsonl
VALIDATE,gs://my-project-lcm/training-data/validatedata.jsonl
TEST,gs://my-project-lcm/training-data/testdata.jsonl
结果与使用
等待的时间还是很漫长的,至少我坐在电脑旁边等了三个小时都没有出训练好的模型。而在此例中我也仅用了千余个数据和一个标签。
我们最终获得了98.1%的precision。鉴于这只是一个测试用的例子,数据集质量并不高,所以我们对evaluation这里不做太多的分析。在test一栏中可以直接使用训练好的模型。Google给我们提供了 REST API 和 python 的使用接口,方便直接在代码中调用训练好的模型。
个人认为,对于用各种特点的对象,还是应当根据对象特点的不同多做标签,以达到更高的精度。这也是接下来,我构建真正要使用的模型要做的事。