电子说
TensorFlow 是一个开放源代码软件库,用于进行高性能数值计算。借助灵活的架构,用户可以轻松地将计算工作部署到多种平台(CPU、GPU、TPU)和设备(桌面设备、服务器集群、移动设备、边缘设备等)。最近在 JS 社区中,对 TF 中 Java API 相关项目与技术的高度需求是前所未有的。
▌TensorFlow v1.9
近日,TensorFlow 发表推文正式发布 TensorFlow v1.9 ,大家可以更新各自的代码啦~~在 TF 的更新文档中更新了 keras,包括一个新的基于keras的入门,一个非常适合初学者的Jupyter 笔记本,还增加了更多的实例。
其中有两个案例受到了大家的广泛关注,这个项目是通过 Colab 在 tf.keras 中训练模型,并通过TensorFlow.js 在浏览器中运行;最近在 JS 社区中,对这些相关项目的高度需求是前所未有的。之前人工智能头条也为大家介绍了一个在浏览器中通过TensorFlow.js 进行多人人脸识别与特征检测的项目,也受到大家的广泛关注。此外 TensorFlow 还给那些想了解、学习相关项目技术的关注者们推出了系列官方教学视频。
今天人工智能头条会带领大家学习这个新项目,JS 爱好者和开发者们不要错过!
另一个项目是简单的RNN网络生成文本的实践,这次作者不仅在GitHub 上分享了源码,大家还可以利用这次 v1.9 中的笔记本新功能来进行端到端的直接运行。
在 Google Colab 中看到这个项目的第一眼,就觉得真的很适合初学者研究学习。左侧可以一目了然地看 “目录” 与 “代码段”。
已经分解的源码结构,从安装、导入需要的工具,到下载读取数据,创建训练模型,最后预测模型,只要跟着一步一步来,相信大家都会学有所成。
▌TensorFlow v1.9 实践
前言
在这个应用中我们将完成通过识别图画来输出当前图画的名称的实践。使用 Google Colab 来训练模型,使用 TensorFlow.js 在浏览器上进行部署,直接在浏览器上运行。需要注意的一点是,务必要在测试 Google Colab 的 notebook 工具:
https://colab.research.google.com/github/zaidalyafeai/zaidalyafeai.github.io/blob/master/sketcher/Sketcher.ipynb
数据集
我们将使用 CNN 来识别不同类型的图画。CNN 将在Quick Draw数据集上进行训练。这个数据集包含了大约5000万张、345类别的图画。
管道
我们将使用 Keras 在 Google Colab 上训练模型,然后通过 TensorFlow.js (tfjs) 在浏览器上直接运行。下图向大家展示了这个项目的管道图
参考教程:
https://js.tensorflow.org/
https://github.com/tensorflow/tfjs-examples
输入
我们将使用带有tensorflow后端的keras:
import osimport globimport numpy as npfrom tensorflow.keras import layersfrom tensorflow import keras import tensorflow as tf
加载数据
由于内存有限,我们不会在所有的类别进行训练。我们只使用100个类别的数据集。在Google Cloud 的quickdraw_dataset 上每个类别的数据都可以用形状表示为 [N,784] 的numpy数组,其中 N 是该特定类的的图像数量。我们首先下载数据集:
import urllib.requestdef download(): base = 'https://storage.googleapis.com/quickdraw_dataset/full/numpy_bitmap/' for c in classes: cls_url = c.replace('_', '%20') path = base+cls_url+'.npy' print(path) urllib.request.urlretrieve(path, 'data/'+c+'.npy')
由于内存有限,因此每个类只能加载5000个图像到内存。另外还保留了20%的用于测试的数据。
def load_data(root, vfold_ratio=0.2, max_items_per_class= 5000 ): all_files = glob.glob(os.path.join(root, '*.npy')) #initialize variables x = np.empty([0, 784]) y = np.empty([0]) class_names = [] #load a subset of the data to memory for idx, file in enumerate(all_files): data = np.load(file) data = data[0: max_items_per_class, :] labels = np.full(data.shape[0], idx) x = np.concatenate((x, data), axis=0) y = np.append(y, labels) class_name, ext = os.path.splitext(os.path.basename(file)) class_names.append(class_name) data = None labels = None #separate into training and testing permutation = np.random.permutation(y.shape[0]) x = x[permutation, :] y = y[permutation] vfold_size = int(x.shape[0]/100*(vfold_ratio*100)) x_test = x[0:vfold_size, :] y_test = y[0:vfold_size] x_train = x[vfold_size:x.shape[0], :] y_train = y[vfold_size:y.shape[0]] return x_train, y_train, x_test, y_test, class_names
预处理数据
我们对数据进行预处理,为训练做准备。该模型将采用 [N, 28, 28, 1] 批次 并输出为 [N, 100] 的概率。
# Reshape and normalizex_train = x_train.reshape(x_train.shape[0], image_size, image_size, 1).astype('float32')x_test = x_test.reshape(x_test.shape[0], image_size, image_size, 1).astype('float32')x_train /= 255.0x_test /= 255.0# Convert class vectors to class matricesy_train = keras.utils.to_categorical(y_train, num_classes)y_test = keras.utils.to_categorical(y_test, num_classes)
创建模型
我们将创建一个简单的CNN。参数数量越少,模型就越简单越好。因为我们是在浏览器上进行转换后运行模型,并且希望模型能够快速运行以便进行预测。下面模型包含了3个conv层和2个dense层。
# Define modelmodel = keras.Sequential()model.add(layers.Convolution2D(16, (3, 3), padding='same', input_shape=x_train.shape[1:], activation='relu'))model.add(layers.MaxPooling2D(pool_size=(2, 2)))model.add(layers.Convolution2D(32, (3, 3), padding='same', activation= 'relu'))model.add(layers.MaxPooling2D(pool_size=(2, 2)))model.add(layers.Convolution2D(64, (3, 3), padding='same', activation= 'relu'))model.add(layers.MaxPooling2D(pool_size =(2,2)))model.add(layers.Flatten())model.add(layers.Dense(128, activation='relu'))model.add(layers.Dense(100, activation='softmax')) # Train modeladam = tf.train.AdamOptimizer()model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['top_k_categorical_accuracy'])print(model.summary())
适配、验证和测试
在此之后,我们对模型进行了5个轮数和256个批次的训练,并进行了10%的验证划分:
#fit the model model.fit(x = x_train, y = y_train, validation_split=0.1, batch_size = 256, verbose=2, epochs=5)#evaluate on unseen datascore = model.evaluate(x_test, y_test, verbose=0)print('Test accuarcy: {:0.2f}%'.format(score[1] * 100))view raw
训练的结果如下图所示:
测试准确率中第5个准确率为92.20%。
为Web格式准备模型
在我们对模型的准确率感到满意之后,我们将其保存并准备进行转换:
model.save('keras.h5')
安装tfjs包进行转换:
!pip install tensorflowjs
然后转换模型:
!mkdir model!tensorflowjs_converter --input_format keras keras.h5 model/
创建了一些权重文件和包含模型体系结构的json文件。
压缩模型,准备将其下载到我们的本地计算机中:
!zip -r model.zip model
最后下载模型:
from google.colab import filesfiles.download('model.zip')
下面将展示如何加载模型并进行推理。假设我们有一个 300x300 大小的画布。
加载模型
要使用TensorFlow.js,请首先运行以下脚本:
注意:需要在本地计算机上运行服务器,
然后,使用浏览器加载模型(await 关键字用于等待浏览器加载模型)
model = await tf.loadModel('model/model.json')view raw
预处理
在做预测之前,我们需要先对数据进行预处理。首先从画布中获取图像数据变量 dpi 用于根据屏幕像素的密度对画布进行拉伸。
//the minimum boudning box around the current drawingconst mbb = getMinBox()//cacluate the dpi of the current window const dpi = window.devicePixelRatio//extract the image data const imgData = canvas.contextContainer.getImageData(mbb.min.x * dpi, mbb.min.y * dpi, (mbb.max.x - mbb.min.x) * dpi, (mbb.max.y - mbb.min.y) * dpi);
我们将画布当前的图像数据转换为一个张量,调整大小并进行规范化。
function preprocess(imgData){return tf.tidy(()=>{ //convert the image data to a tensor let tensor = tf.fromPixels(imgData, numChannels= 1) //resize to 28 x 28 const resized = tf.image.resizeBilinear(tensor, [28, 28]).toFloat() // Normalize the image const offset = tf.scalar(255.0); const normalized = tf.scalar(1.0).sub(resized.div(offset)); //We add a dimension to get a batch shape const batched = normalized.expandDims(0) return batched})}
对于预测,我们使用 model.predict ,这将返回形状的概率 [N, 100]:
const pred = model.predict(preprocess(imgData)).dataSync()
然后我们可以用简单的函数来求前5个概率。
提高准确率
记住,我们的模型接受形状 [N, 28, 28,1] 的张量,绘图画布大小为 300x300 ,对于绘图来说,可能需要两个大的用于绘图,或者可能需要用户绘制小一些的图。最好只裁剪包含当前图画的框。为了做到这一点,我们通过查找左上角和右下角来提取绘图周围的最小边界框:
//record the current drawing coordinates function recordCoor(event){ //get current mouse coordinate var pointer = canvas.getPointer(event.e); var posX = pointer.x; var posY = pointer.y; //record the point if withing the canvas and the mouse is pressed if(posX >=0 && posY >= 0 && mousePressed) { coords.push(pointer) } }//get the best bounding box by finding the top left and bottom right cornders function getMinBox(){ var coorX = coords.map(function(p) {return p.x}); var coorY = coords.map(function(p) {return p.y}); //find top left corner var min_coords = { x : Math.min.apply(null, coorX), y : Math.min.apply(null, coorY) } //find right bottom corner var max_coords = { x : Math.max.apply(null, coorX), y : Math.max.apply(null, coorY) } return { min : min_coords, max : max_coords }}
测试绘图
下图展示了一些第一次绘图和最高百分比级别。所有的图画都是我用鼠标绘制的。如果用一支电脑绘图笔可以获得更好的准确率:
全部0条评论
快来发表一下你的评论吧 !