书本:来吧,证明你爱我的时候到了。

机器学习 · jack · Created at · Last by a_z789 Replied at · 310 hits
434 1549005614

项目体验地址:http://at.iunitv.cn/

效果预览:

花絮:

很多小伙伴嘴上说着学不动了,其实身体还是很诚实的。

毕竟读书还是有很多好处的:比如让你的脑门散发智慧的光芒,再或者让你有理由说因为读书太忙了所以没有女朋友等等。

今天我们也想要借助这个机会,普及一下Tensorflow相关的知识,我们会用TensorFlow.js做一个图书识别的模型,并在Vue Application中运行,赋予网页识别图书的能力。

本文讲述了AI相关的概念知识和如何运用SSD Mobile Net V1模型进行迁移学习的方法,从而帮助大家完成一个可以在网页上运行的图书识别模型。

【文末有活动哦】

正文:

什么是迁移学习

迁移学习和域适应指的是在一种环境中学到的知识被用在另一个领域中来提高它的泛化性能。——《深度学习》,第 526 页

再简单一点理解,以今天图书识别模型训练为例,我们利用前人训练好的具备图片识别能力的AI模型,保留AI模型中对图片特征提取的能力的基础上再训练,使AI模型具备识别图书的能力。

迁移学习能够大大提高模型训练的速度,并达到相对不错的正确率。

而我们今天所要迁移学习的对象就是SSD Mobile Net V1模型,初次接触神经网络的同学可以将其理解为一种具备图片识别的轻便小巧的AI模型,它能够在移动设备上高效地运行。对这个模型具体的神经网络设计结构感兴趣的同学可以自行搜索。

了解了基本的概念之后,我们便开始动手吧!我们可以基于SSD Mobile Net模型去设计一个属于自己的AI模型,并让它在Vue Application中运行。

Object Detection(目标识别)

本次项目是为了训练一个Object Detection的模型,即目标识别的模型,该模型能够识别并圈选出图片中相应的目标对象。

准备工作

同步开发环境

为了避免小伙伴因为环境问题遇到各种各样的坑,在工作开展之前,我们先跟大家同步一下运行的环境。大家如果要动手去做,也尽量跟我们的运行环境保持一致,这样可以有效避免踩坑,规避“从入门到放弃”的现象。

开发环境

  • 系统Mac OS系统
  • Python版本:3.7.3
  • TensorFlow版本:1.15.2
  • TensorFlowJS版本:1.7.2
  • 开发工具:Pycharm和Webstorm

下载项目

同步完开发环境后,终于要开始动工了。首先我们需要在Github上下载几个项目:

准备图片素材

我们可以通过搜索引擎收集有关图书的图片素材:

其次,我们可以在Github上克隆LabelImg项目,并根据Github的使用说明,按照不同的环境安装运行LabelImg项目,运行后的页面如下:

然后我们按照以下步骤,将图片格式转换为圈选区域后的XML文件:

  1. 打开图片存放的目录
  2. 选择圈选后的存放目录
  3. 圈选图片目标区域
  4. 设置圈选区域的标签
  5. 保存成XML格式

存放完后我们在存放的目录下会看到许多XML格式的文件,这个文件记录了图片的位置信息、圈选信息和标签信息等,用于后续的模型训练。

配置安装Object Detection的环境

从Github克隆迁移模型训练的项目迁移模型训练项目,注意要在r1.5分支运行,并用PyCharm打开项目。

项目的目录环境为上图,首先我们需要下载TensorFlow1.15.2版本:

pip install tensorflow==1.15.2

其次安装依赖包:

sudo pip install pillow
sudo pip install lxml
sudo pip install jupyter
sudo pip install matplotlib

然后通过终端切换到research目录,并执行几行配置命令,具体请参考Github的使用说明:

cd ./research
protoc object_detection/protos/*.proto --python_out=.
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

最后我们运行model_builder_test.py文件,如果在终端中看到OK字样,表示配置成功。

python object_detection/builders/model_builder_test.py

将XML格式转换为TensorFlow需要的TFRecord格式

克隆并打开图片格式转换项目,然后我们对该项目加以小改造:

改造文件目录:

  1. 删除annotationsdatatraining目录中的内容
  2. 增加一个xmls目录,用以存放xml文件

改造文件:
接着,我们再改造以下2个文件并新增一个文件,方便我们转换图片格式

  1. 改造xml_to_csv.py为:
   import os
   import glob
   import pandas as pd
   import xml.etree.ElementTree as ET
   import random
   import time
   import shutil

   class Xml2Cvs:
       def __init__(self):
           self.xml_filepath = r'./xmls'
           self.save_basepath = r"./annotations"
           self.trainval_percent = 0.9
           self.train_percent = 0.85

       def xml_split_train(self):

           total_xml = os.listdir(self.xml_filepath)
           num = len(total_xml)
           list = range(num)
           tv = int(num * self.trainval_percent)
           tr = int(tv * self.train_percent)
           trainval = random.sample(list, tv)
           train = random.sample(trainval, tr)
           print("train and val size", tv)
           print("train size", tr)
           start = time.time()
           test_num = 0
           val_num = 0
           train_num = 0
           for i in list:
               name = total_xml[i]
               if i in trainval:
                   if i in train:
                       directory = "train"
                       train_num += 1
                       xml_path = os.path.join(os.getcwd(), 'annotations/{}'.format(directory))
                       if (not os.path.exists(xml_path)):
                           os.mkdir(xml_path)
                       filePath = os.path.join(self.xml_filepath, name)
                       newfile = os.path.join(self.save_basepath, os.path.join(directory, name))
                       shutil.copyfile(filePath, newfile)
                   else:
                       directory = "validation"
                       xml_path = os.path.join(os.getcwd(), 'annotations/{}'.format(directory))
                       if (not os.path.exists(xml_path)):
                           os.mkdir(xml_path)
                       val_num += 1
                       filePath = os.path.join(self.xml_filepath, name)
                       newfile = os.path.join(self.save_basepath, os.path.join(directory, name))
                       shutil.copyfile(filePath, newfile)
               else:
                   directory = "test"
                   xml_path = os.path.join(os.getcwd(), 'annotations/{}'.format(directory))
                   if (not os.path.exists(xml_path)):
                       os.mkdir(xml_path)
                   test_num += 1
                   filePath = os.path.join(self.xml_filepath, name)
                   newfile = os.path.join(self.save_basepath, os.path.join(directory, name))
                   shutil.copyfile(filePath, newfile)

           end = time.time()
           seconds = end - start
           print("train total : " + str(train_num))
           print("validation total : " + str(val_num))
           print("test total : " + str(test_num))
           total_num = train_num + val_num + test_num
           print("total number : " + str(total_num))
           print("Time taken : {0} seconds".format(seconds))

       def xml_to_csv(self, path):
           xml_list = []
           for xml_file in glob.glob(path + '/*.xml'):
               tree = ET.parse(xml_file)
               root = tree.getroot()
               print(root.find('filename').text)
               for object in root.findall('object'):
                   value = (root.find('filename').text,
                            int(root.find('size').find('width').text),
                            int(root.find('size').find('height').text),
                            object.find('name').text,
                            int(object.find('bndbox').find('xmin').text),
                            int(object.find('bndbox').find('ymin').text),
                            int(object.find('bndbox').find('xmax').text),
                            int(object.find('bndbox').find('ymax').text)
                            )
                   xml_list.append(value)
           column_name = ['filename', 'width', 'height', 'class', 'xmin', 'ymin', 'xmax', 'ymax']
           xml_df = pd.DataFrame(xml_list, columns=column_name)
           return xml_df

       def main(self):
           for directory in ['train', 'test', 'validation']:
               xml_path = os.path.join(os.getcwd(), 'annotations/{}'.format(directory))
               xml_df = self.xml_to_csv(xml_path)
               xml_df.to_csv('data/mask_{}_labels.csv'.format(directory), index=None)
               print('Successfully converted xml to csv.')


   if __name__ == '__main__':
       Xml2Cvs().xml_split_train()
       Xml2Cvs().main()
  1. 改造generate_tfrecord.py文件,将csv格式转换为TensorFlow需要的record格式:

将该区域的row_label改成我们LabelImg中的标签名,因为我们只有一个标签,所以直接修改成book即可。

  1. 新增一个generate_tfrecord.sh脚本,方便执行generate_tfrecord.py文件
   #!/usr/bin/env bash
   python generate_tfrecord.py --csv_input=data/mask_train_labels.csv  --output_path=data/mask_train.record --image_dir=images
   python generate_tfrecord.py --csv_input=data/mask_test_labels.csv  --output_path=data/mask_test.record --image_dir=images
   python generate_tfrecord.py --csv_input=data/mask_validation_labels.csv  --output_path=data/mask_validation.record --image_dir=images

配置Object Decation的环境

export PYTHONPATH=$PYTHONPATH:你的models/research/slim所在的全目录路径

最后我们将图片文件复制到images目录,将xml文件复制到xmls目录下,再执行xml_to_csv.py文件,我们会看到data目录下产生了几个csv格式结尾的文件;这时,我们在终端执行generate_tfrecord.sh文件,TensorFlow所需要的数据格式就大功告成啦。

image-20200420172821520.png

迁移训练模型:

在这个环节我们要做以下几件事:

  • 将刚刚生成好的record文件放到对应目录下
  • 下载SSD Mobile Net V1模型文件
  • 配置book.pbtxt文件和book.config文件
放置record文件和SSD Mobile Net V1模型

为了方便我直接将models/research/object_detection/test_data下的目录清空,放置迁移训练的文件。

首先我们下载SSD Mobile Net V1模型文件

我们下载第一个ssd_mobilenet_v1_coco模型即可,下载完毕后,我们解压下载的模型压缩包文件,并将模型相关的文件放在test_datamodel目录下。并将我们刚刚生成的record文件放置在test_data目录下。

完成pbtxt和config配置文件

我们在test_data目录下,新建一个book.pbtxt文件,并完成配置内容:

item {
  id: 1
  name: 'book'
}

由于我们只有一个标签,我们就直接配置一个id值为1,name为book的item对象。

由于我们使用SSD Mobile Net V1模型进行迁移学习,因此我们到sample\configs目录下复制一份ssd_mobilenet_v1_coco.config文件并重命名为book.config文件。

接着我们修改book.config中的配置文件:

将num_classes修改为当前的标签数量:

由于我们只有一个book标签,因此修改成1即可。

修改所有PATH_TO_BE_CONFIGURED的路径:
<center>
<img src="https://user-gold-cdn.xitu.io/2020/4/23/171a5d916b7213e0?w=1410&h=982&f=png&s=147351" style="zoom:50%;" />
</center>

我们将此处的模型文件地址设置成testdata/model/model.ckpt的全路径地址。

我们将train_input_readerinput_path设置成mask_train.record的全路径地址;将label_map_path设置成book.pbtxt的全路径地址;将eval_input_readerinput_path设置成mask_test.record的全路径地址。

到目前为止我们所有配置都已经完成啦。接下来就是激动人心的训练模型的时刻。

运行train.py文件训练模型

我们在终端中运行train.py文件,开始迁移学习、训练模型。

python3 train.py --logtostderr --train_dir=./test_data/training/ --pipeline_config_path=./test_data/book.config

其中train_dir为我们训练后的模型存放的目录,pipeline_config_path为我们book.config文件所在的相对路径。

运行命令后,我们可以看到模型在进行一步一步的训练:

并在/test_data/training目录下存放训练后的模型文件:

<center>
<img src="https://user-gold-cdn.xitu.io/2020/4/23/171a5db65704e6e0?w=610&h=842&f=png&s=140510" style="zoom:50%;" />
</center>

将ckpt文件转换为pb文件

我们通过export_inference_graph.py文件,将训练好的模型转换为pb格式的文件,这个文件格式在后面我们要用来转换为TensorFlow.js能够识别的文件格式。终于我们见到TensorFlow.js的影子啦。

<center>
<img src="https://user-gold-cdn.xitu.io/2020/4/23/171a5dbee720cc2c?w=440&h=439&f=jpeg&s=20529" style="zoom:50%;" />
</center>

我们执行命令,运行export_inference_graph.py文件:

python export_inference_graph.py --input_type image_tensor --pipeline_config_path ./test_data/book.config --trained_checkpoint_prefix ./test_data/training/model.ckpt-1989 --output_directory ./test_data/training/book_model_test

其中pipeline_config_pathbook.config的相对文件路径,trained_checkpoint_prefix为模型文件的路径,例如我们选择训练了1989步的模型文件,output_directory为我们输出pb文件的目标目录。

运行完后,我们可以看到一个生成了book_model_test目录:

将pb文件转换为TensorFlowJs模型

首先我们需要依赖TensorFlowjs的依赖包

pip install tensorflowjs

然后通过命令行转换刚刚生成的pb文件

tensorflowjs_converter --input_format=tf_saved_model --output_node_names='detection_boxes,detection_classes,detection_features,detection_multiclass_scores,detection_scores,num_detections,raw_detection_boxes,raw_detection_scores' --saved_model_tags=serve --output_format=tfjs_graph_model ./saved_model ./web_model

其中我们设置最后两个参数,即saved_model的目录与TensorFlow.js识别模型的输出目录。

运行结束后,我们可以看到一个新生成的web_model目录,其中包括了我们迁移学习训练后的模型。

到这里,模型训练的阶段终于结束了。

在Vue中运行模型

准备工作

新建Vue项目,在Vue项目的public目录下放入我们训练好的模型,即web_model目录。

image-20200421132233993.png

接着我们借助Tensorflow.js的依赖包,在package.jsondependencies中加入:

"@tensorflow/tfjs": "^1.7.2",
"@tensorflow/tfjs-core": "^1.7.2",
"@tensorflow/tfjs-node": "^1.7.2",

然后通过npm命令安装依赖包。

加载模型

在我们的JS代码部分引入TensorFlow的依赖包:

import * as tf from '@tensorflow/tfjs';
import {loadGraphModel} from '@tensorflow/tfjs-converter';

接着第一步,我们先加载模型文件中的model.json文件:

const MODEL_URL = process.env.BASE_URL+"web_model/model.json";
this.model = await loadGraphModel(MODEL_URL);

通过loadGraphModel方法,我们加载好训练的模型,再将模型对象打印出来:

image-20200421132921380.png

随后,我们可以看到模型会输出一个长度为4的数组:

  • detection_scores:表示识别对象模型的置信度,置信度越高,则代表模型认为对应区域识别为书本的可能性越高
  • detection_classes:表示模型识别的区域对应的标签,例如在本案例中,识别出来的是book
  • num_detections:表示模型识别出目标对象的个数
  • detection_boxes:表示模型识别出来目标对象的区域,为一个长度为4的数组,分别是:[x_pos,y_pos,x_width,y_height] 。第一个位代表圈选区域左上角的x坐标,第二位代表圈选左上角的y坐标,第三位代表圈选区域的宽度,第四位代表圈选区域的长度。

模型识别

知道了输出值,我们就可以开始将图片输入到模型中,从而得到模型预测的结果:

const img = document.getElementById('img');
let modelres =await this.model.executeAsync(tf.browser.fromPixels(img).expandDims(0));

我们通过model.executeAsync方法,将图片输入到模型中,从而得到模型的输出值。

结果是我们前文提到的一个长度为4的数组。接着我们通过自定义方法,将得到的结果进行整理,从而输出一个想要的结果格式:

buildDetectedObjects:function(scores, threshold, imageWidth, imageHeight, boxes, classes, classesDir) {
          const detectionObjects = [];
          scores.forEach((score, i) => {
              if (score > threshold) {
                  const bbox = [];
                  const minY = boxes[i * 4] * imageHeight;
                  const minX = boxes[i * 4 + 1] * imageWidth;
                  const maxY = boxes[i * 4 + 2] * imageHeight;
                  const maxX = boxes[i * 4 + 3] * imageWidth;
                  bbox[0] = minX;
                  bbox[1] = minY;
                  bbox[2] = maxX - minX;
                  bbox[3] = maxY - minY;
                  detectionObjects.push({
                      class: classes[i],
                      label: classesDir[classes[i]].name,
                      score: score.toFixed(4),
                      bbox: bbox
                  });
              }
          });

          return detectionObjects
}

我们通过调用buildDetectedObjects来整理和返回最后的结果。

  • scores:输入模型的detection_scores数组
  • threshold:阈值,即结果score>threshold我们才会将对应的结果放入结果对象detectionObjects
  • imageWidth:图片的宽度
  • imageHeight:图片的长度
  • boxes:输入模型的detection_boxes数组
  • classes:输入模型的detection_classes数组
  • classesDir:即模型标签对象

调用buildDetectedObjects方法示例:

let classesDir = {
    1: {
        name: 'book',
        id: 1,
        }
    };
let res=this.buildDetectedObjects(modelres[0].dataSync(),0.20,img.width,img.height,modelres[3].dataSync(),modelres[1].dataSync(),classesDir);

我们通过modelres[0].dataSync(),来获取对应结果的数组对象,再输入到方法中,从而最终获得res结果对象。

image-20200421140000851.png

最后我们通过Canvas的API,将图片根据bbox返回的数组对象,画出对应的区域即可。由于篇幅原因,就不赘述了,最终效果如下:
image-20200421140314124.png

最后

本案例的模型存在一定的不足,由于训练时间较短,图书的封面类型众多,存在人像、风景图等等的样式,导致模型在识别过程中可能会将少部分的人脸、风景照等图片错误地识别成图书封面。各位小伙伴在训练自己模型的过程中可以考虑优化此问题。

当然,本案例的模型在识别非图书的场景会存在识别不准确的情况,一方面这是因为本案例从网络收集的图书样本具有一定局限性,而且图书的封面类型千差万别,存在人像、风景图等等的样式;另一方面因为本文在仅为起到抛砖引玉的作用,为各位前端小伙伴普及TensorFlow.js相关的知识,并提供训练自己的模型的解决方案,所以在收集样本和模型训练时间较短。感兴趣的小伙伴可以自己琢磨琢磨如何优化样本和在避免过拟合的情况下提高训练时长,从而提高模型对被识别物体的准确性。

我们写下本文仅为起到抛砖引玉的作用,为各位前端小伙伴普及TensorFlow.js相关知识并提供一种AI的解决方案。

我们希望和广大程序员一起学习新知、共同进步,愿每位热爱学习的开发者都能畅游书海,遇见更好的自己!

共收到 2 条回复
1Floor Deleted
8318 1590503647
a_z789 · #2 ·

台灣約炮叫小姐找傲嬌幼熙看照約妹~膝外送茶莊一夜情外送茶加賴ut6088 [賴:av051] [SK: anvo369] [Telegram:GTO6885]
深夜寂寞就加賴ut6088甜蜜蜜的雙唇 添上你的大肉棒口技交術好
1:可獨享VIP會員專線 “一撥即通 暢通無阻”
2:品質好茶優先推薦
3:每次消費都可享受八折折扣

4:帶朋友消費即可得到一張2K的優惠卷
5:可看部分妹妹不遮臉真人照加賴ut6088 [ 賴2:av051] [SK: anvo369] [Telegram:GTO6885]
★更多精彩好茶 更多天然美女盡在【右熙看照約妹約炮論壇】
★每天上百名兼職靚妹 等待哥哥們的邀喲
★服務地區:台北 台中 彰化 南投 高雄 新竹 台南 新北
【買二節可免費送二節的優惠活動喔】加賴ut6088 [賴2:av051] [SK: anvo369] [Telegram:GTO6885]
右熙將熱情24h為您服務,讓你喝到更多好茶,享受更多優質服務
右熙外送茶賴ut6088 賴2:av051 【賴3:204078】有奶水人妻敢玩內射配合你的需求滿足你讓你吃飽 學生妹、無套妹、淫蕩大奶的
高挑美腿的、淫蕩會玩的、雙飛3P等等(一龍二鳳).....很多正妹資訊+優惠方案 加賴可以去了解喲!!!)加賴ut6088每日更新勁爆
可看裡面更多新妹兼職的資訊哦!消費一次可加入VIP帳號
便可獲得VIP密碼 VIP專區:可看影片約妹瀨ut6088 [瀨2:av051] [SK: anvo369] [Telegram:GTO6885]
賴ut6088右熙外送茶北中南奶水人妻茶坊口爆處女爆乳無套約妹
◤銷魂的台灣,激情的夜晚嫵媚的身體所有男人的崇拜對象◥
◤正妹預約趁現在,激情愛愛趁現在喔 MT HT 住家 自選喔◥
◤性福區域:台中、台北、高雄、彰化、南投、新竹、桃園,台南 香港。日本◥
全套服務:洗香香 愛撫 口交 按摩 S 愛愛 69 清水溝 角色扮演(可無套 可多P唷)
PS:想要特殊服務的要提前跟我講喔瀨ut6088 [瀨2:av051] [SK: anvo369] [Telegram:GTO6885]

最強陣容- 實在價位 - 每天不斷更新 -各行各業兼職正妹 任君挑選
各行各業 -不同的規矩 - 全套服務 - 安全第一瀨ut6088
奶水人妻茶坊口爆處女爆乳無套約妹瀨ut6088 [賴2:av051] [SK: anvo369] [Telegram:GTO6885]
以下MM私賴我看她們的照片喔!現在約還可以優惠的3000優惠折扣喲
服務:69 按摩 洗澡 口交 後門 無套 中出 口爆基本服務+特別服務
幼熙外送本土茶瀨ut6088 [賴2:av051] [SK: anvo369] [Telegram:GTO6885]只要配合一次升級VIP就是永久的半價之後約小姐無套內射旅館費一律免費 可以加入色群(裏面是19-23歲的女孩子裏面有影片可以裸照視訊+賴ut6088)送原味內褲絲襪

1.從此約妹妹半價
2.從此幫出旅館費用
3.從此無需在給車資
4.從此無套內射不用加小費
5.從此跳蛋 絲襪 情趣服裝 用品隨你選
6.從此約會地點隨你定也可妹去見朋友
7.從此看妹妹自慰影片選妃
8.從此升級本茶莊vip 優先約到各種高品質小姐
【空姐 AV女優 小有名氣的麻豆和Show Girl 兩男一女的3p或者兩男兩女的4p中日混血-中韓混血-中俄混血-中英混血-中巴混血-中泰混血-中法混血 處女 人妖(處女和人妖少之又少需提前一周預約)[瀨ut6088] [瀨2:av051] [SK: anvo369] [Telegram:GTO6885]
加入賴ut6088 [賴2:av051][SK: anvo369] [Telegram:GTO6885]即可看主頁無碼真人自慰 可以視訊選妹還有處女 另有奶水人妻現場擠奶視訊18歲處女跟客人做愛無碼照 高檔貨色空姐私密照外露 三嫌藝人偶爾兼職 免費摸奶 加入立減2000約妹妹 加入有優惠唷瀨ut6088 [瀨2:av051] [SK: anvo369] [Telegram:GTO6885]

空姐 模特兒 演藝明星 女主播 護士 女軍官 AV女優 運動員 女學生 促 狂野型 淫盪型 服務型 外貿型 氣質型 美腿型 甜美型 大型 高檔型 特別型 火辣 台北/新竹/台中/彰化/南投/高雄市區 住家、飯店、商汽旅(見到妹妹/滿意金消費)+賴ut6088╭適時點杯台灣好TEA╮★╭新鮮出爐ㄉ好茶等你來泡!!絕對驚艷![應有盡有~任君挑選☆服務超優] 台北/台中/高雄/彰化/新竹/茶訊論壇/鐘點情人外送茶/找茶喝/找魚論壇/高價正妹外送茶/高價辣妹外送高價清純學生妹/高價麻豆外送/高價混血正妹外送/出差外叫小姐/外送到府 成人愛愛論壇 大家來找茶 伊利 玩美情人 約妹+賴ut6088男人幫 QK情色休閒俱樂部重車論壇 一夜情 瀘州指壓 成人圖片 李宗瑞 陳自搖 口爆 幼幼 成人貼圖 吳亞馨 中出 顏射 太子 找魚論壇 陳自搖 鬆島楓 大台灣高

雄右熙外送茶坊喝茶吃魚/外約美女俱樂部/外送正妹/.好茶正妹辣妹茶訊論壇 有照參考/純兼職學生妹外送/旅館叫小姐/台中外送住家外約愛愛茶外送GTO,台灣一夜

情, 高雄一夜情,台中一夜情,台北一夜情,台北美女外約,台中美女外約,高雄美女外約,高雄茶莊 ,台中茶莊,台北茶莊,台北叫小姐+賴ut6088 台中叫小姐,高雄叫小姐,高雄外約, 台北美女外約,台中美女外約彰化正妹外約,高雄美女外約,高雄汽車旅館叫小姐, 高雄找小約妹+瀨ut6088 賴2:av051 茶姐,高雄外送茶坊,全套服務,高雄美女外送,台灣優質好茶,好茶

分享,AV女優, 清純大學生激情愛愛,高雄茶莊外送,高雄援交妹外約,台灣援交妹,吃魚喝茶論壇+瀨ut6088, 大家來找茶,PLUS,伊利,EYNY,玩美情人,男人幫,高雄鐘點

情人,高雄美女外約,高雄外送, 高雄賓館叫小姐高雄飯店叫小姐,高雄鐘點情人外約,台北旅館叫小姐,台北鐘點情人, 彰化外送茶,台灣兼職美女外送,台北兼職美女外約,台中外送茶坊,高雄外坊,台北外送茶坊板橋外送到府/台北高檔茶/喝茶/彰化找茶喝/愛愛茶/找茶網/永和外送住家叫小姐/ 汐止找魚論壇/林口魚訊網/茶討論區/瀘州指壓/淡水

旅館飯店叫小姐/土城出差叫小姐 台北外約正妹學生愛愛/新店找女人開房/加賴ut6088 賴2:av051現金消費/士林外送服務/板找茶網/ 台北酒店叫小姐/找魚論壇/外送到府/茶莊簡介/外約愛愛/外約電話/旅館飯店叫小姐

正妹外送服務/外約高檔茶/找茶論壇到府服務外送夜店辣妹+賴ut6088外送住家學生妹/外送旅館找女人 /外送浪漫一夜情/外送鐘點情人 (限台北縣市 台中縣市)[+賴ut6088] [賴2:av051 [SK: anvo369] [Telegram:GTO6885]非誠勿擾 莊外叫茶/新店正妹介紹/板橋外送茶到府/台北高檔茶/喝茶/彰化找茶喝/愛愛茶/找茶網 /永和外送住家叫小姐/汐止找魚論壇/

林口網/找茶討論區/瀘州指壓/淡水旅館飯店叫小姐 土城出差叫小姐/台北外約正妹學生愛愛/新店找女人開房/現金消費/士林外送務板橋找茶網 /台北酒店叫小姐/找魚論壇/約妹+賴ut6088外

送到府/茶莊簡介/外約愛愛/外約電話旅館飯店叫小姐 /正妹外送服務/外約高檔茶/茶論壇/(惡意廣告)/找茶夜情外送辣妹鐘點情人兼職學生妹 成人愛愛論壇高雄左營新興外+

瀨ut6088 賴2:av051 送茶魚訊網想讓自己有個激情的台北台彰化南投外送茶.吃魚喝茶找茶.出差飯店酒店旅館叫茶.叫女人.飯店叫辣妹.外約電話.外送人妻辣媽.汐止.瀘州.三重.新莊.南港.林口龜山外

送茶.台北舒壓按摩全套服務外送.援交妹網站.全套服務網站台北外送茶.外送住家.一夜情.外送鐘點情人外送茶坊台北竹賴ut6088 賴av051 彰化台中高雄南投彰化旅館飯店叫小姐+賴ut6088找炮友最佳選擇地方

哪家找小姐最好首推頂級優質女王.右熙外送茶坊瀨ut6088 [賴2:av051] [ SK: anvo369] [Telegram:GTO6885]高雄外送茶莊/高雄女外送旅館叫小姐台中外送茶/高雄外送茶高雄外送茶莊/ MOTEL外送茶. 台中應召站外送茶. 台中資訊學生妹+賴ut6088

右熙外送茶+瀨ut6088有奶水人妻敢玩內射配合你的需求滿足你讓你吃飽. 台中喝茶 一夜 頂優質女王.+賴ut6088右熙/台北外送茶/台中

外送茶高雄外送茶/吃魚喝茶論壇/援交妹網站/FB交友網站/漁會美人/伊莉討論區 右熙外約茶坊賴ut6088 [賴2:av051]【SK: anvo369】 [Telegram:GTO6885]

賴ut6088 [賴2:av051][SK: anvo369] [Telegram:GTO6885]歡迎加入我們小三茶園將細心幫哥哥挑選每一位心怡的正妹

《小三慾茶園》各類妹妹任君挑選 期待相遇 加北部LINE: av051 中南部瀨ut6088活潑可愛的學生妹--清純嬌小的小護士-- 楚楚動人的幼教老師--勁爆火辣的OL-

性感迷人的專櫃--魔鬼身材的麻豆-- 服務好--價位優--年紀輕-- 各式各樣兼職美媚應有盡有兼職妹妹=優質服務=見面滿意再消費--安全--滿意--就是我們的服務 加節更有刺激特殊服務:

【Kiss】【LDS】【乳交】【肛交】【69】【顏射】 【角色扮演】【火車便當】【毒龍鑽】【無套口交】...詳情線上資訊 小三外約情人LINE 加北部LINE: av051中南部av051

台中外送茶 西屯外送茶 西屯約小姐 北屯約小姐 台中之星 水雲端 台中叫小姐 台中出差找小姐高雄叫小姐 台南叫小姐 台南外約小姐 台灣叫小姐LINE:ut6088 [賴2:av051] [SK: anvo369] [Telegram:GTO6885]北投泡溫泉找妹陪/北投外約找旅館/

北投外約小姐/北投找無套妹/溫泉旅館叫小姐 金錢豹酒店小姐 板橋外送茶到府/永和外送住家叫小姐/旅館飯店叫小姐/新竹找茶網/ 酒店叫小姐/新店找女人開房/士林外送服務/台北木柵喝茶/ 永和叫服務按摩好茶外送台北/3p玩法無套正妹/台北南港外約 鐘點情人/林口薇閣一夜情賴ut6088 [賴2:av051] [SK: anvo369] [Telegram:GTO6885]/台北汐止慾望援助妹/

台北土城叫小姐/ 台北大安區找女人開房/台北新莊雅緹找小姐/板橋金色年代/ 台北萬華區叫妹/外約八大娛樂網/第三者指油壓/一夜情留言板/ 台北中正區叫茶/台北松山區一等好找女人/喝茶吃魚論壇/

情賴ut6088 [賴2:av051] [SK: anvo369][Telegram:GTO6885]/台北旅館飯店找服務叫小姐/ 找女人全套服務/成人夜遊/魚訊交流論壇區/台灣茶/外國妞妞/日韓泡菜妹 臺北/臺中/高雄/彰化/新竹/茶訊/鐘點情人外送茶找茶出差外叫成人愛

愛論壇伊利玩美情人全套半套賴ut6088 [賴2:av051] [SK: anvo369] [Telegram:GTO6885]男人幫QK情色休閒俱樂部重車論壇一夜情瀘州指壓

臺北/臺中/高雄/彰化/新竹/茶訊/鐘點情人外送茶 找茶出差外叫成人愛愛論壇/伊利/玩美情人/全套/半套男人幫QK情色休閒俱樂部重車論壇一夜情瀘州指壓 清純學生妹/東海大學/靜宜大學/高雄85大樓叫小姐賴av051/台南叫小姐/高雄御宿旅館/台中之星/台中外送住家/台中外約叫小姐/台中西 區叫小姐/台中西屯叫小姐/小女人論壇/香港出差台灣叫小姐/港姐/趙麗穎/伊利論壇/

捷克論壇/卡提偌論壇/茶魚論壇/85論壇/8tv論壇/鄧紫棋/田馥甄還是要幸福/泡沫/謝和絃/goole/部落格/台北健身房/W飯店/君閣酒店/8tv論壇/啪啪啪論壇/8v論壇/男人幫論壇/女人俱樂部/貓都論壇/北投溫泉/北投溫泉旅館/東升雲新聞/遊戲主播/蘋果動新聞/溫泉旅館/北投新北投陽明山便宜平價溫

泉泡湯/湯屋/大眾池/新竹約小姐/大S剝蝦論/好玩、小遊戲、性感、激情、一夜情、成人、網愛、交友、辣妹、美女、線上、ut、豆豆、影音、視訊、聊天室、寫真、自拍、貼圖、圖片、聊天、影片、電影、下載、好玩、小遊戲、統一發票、找工作、大樂透、摸摸耳、百人斬、挖挖吧、夜店、瑤瑤、六合彩、無名、網誌、部落格、相簿、單身、男女、浪漫、婚友、旅遊、美食、笑話、無碼、情人、手機、團購、汽車、旅館、街舞、微風、A片、AV、女優、視訊、美女、交友、聊天室、色情、網站、星座、油價、查詢、話題、股市、新聞、地圖、理財、家族、正妹牆、欣賞、軟體、程式、情色、文學、論壇、中文、防毒、動漫熱舞 美女、正妹、巨乳、爆乳、名模、模特兒、遊戲、絲襪、美腿、人妻、桌布、寫真集、聊天室、鬼片、鬼故事、電腦、網路、娛樂、笑話、圖庫、明星、室內裝 修、室內設計、風水、地理、星座、生肖 竹科約小姐 竹北約小姐大家來找茶,PLUS,伊利,eyny,玩美情人,男人幫,高雄鐘點情人,高雄美女外約,高雄外送,大奶妹大奶妹 G奶妹 H奶妹 E奶妹大奶妹 G奶妹 H奶妹 E奶妹大奶妹 G奶妹 E奶妹 AV女優 明日花 西門町找小姐 一夜情聊天室 靜宜學生妹加賴av051 高雄賓館叫小姐,高雄飯店叫小姐,高雄鐘點情人外約,台北旅館叫小姐,台北鐘點情人,台灣S Hotel 歐游汽車旅館 香港出差找小姐 新店約小姐高雄樹德學生妹賴ut6088 [賴2:av051] 【賴3:204078】[SK: anvo369] [Telegram:GTO6885] 彰化外送茶,台灣兼職美女外送,台北兼職美女外約,台中外送茶坊,高雄外送茶坊,

台北外送茶坊 大奶妹 G奶妹 H奶妹 E奶妹 台大學生妹兼職賴ut6088 [賴2:av051] [SK: anvo369] [Telegram:GTO6885]喝茶/彰化找茶喝/愛愛茶/找茶網/永和外送住家叫小姐加賴av051/大奶妹 G奶妹 H奶妹 E奶妹 汐止找魚論壇/林口魚訊網/找茶討論區/瀘州指壓/淡水旅館飯店叫小姐/土城出差叫小姐/人妻兼職/大奶妹 G奶妹 H奶妹 E奶妹 僑光學生妹兼職加賴av051

台灣外送茶找小姐約炮官網:http://ut6088.pixnet.net/blog/post/6481748
雙北外送茶找小姐約炮網站:https://twitter.com/vaSmwyRxp0HTiuu
台中外送茶找小姐約炮網站:https://ut6088111.blogspot.com/
高雄外送茶找小姐約炮網站:https://ut6088.weebly.com/

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up