前端探索深度学习指北

背景

近年来Javascript生态链的繁荣发展,前端工程师早已不是当年的"切图仔"。Node.js的出现让前端工程师也能写服务端,随之而来诸如webpack等工具链结合MVVM框架更是让前端迈入工程化、组件化的时代。再后来ReactNative又让前端开发跨平台APP成为了可能。如今随着硬件性能的提升,以及WebGL的GPU计算能力,Tensorflow.js让前端有了做深度学习的能力。

作为前端的该关注的

如果你在百度或者知乎搜索这个问题,十有八九会被劝退,因为这些答案不是面向前端的。答案里大多包含数学公式、算法、以及大神的入门视频课程。诚然良好的基础确实决定了未来能走多远。但是我们需要明确的是:我们并不是要转行当算法工程师,更不是去发明一个新的模型算法,我们要学习的只是合理的调用大神封装好的算法来服务于业务。 俗称调包侠,真正做研究的屈指可数,就好比咱们前端都用react、vue但是也不需要自己开发它一样,你不懂原理也可以用它做需求。

在入门前你只需要具备:

  • 基本的矩阵运算知识(加减乘除)
  • python基础(虽然我们最后是用jsAPI,但是学习过程中很多case都是python实现,起码你得看懂)
  • 好像...没了

PS:后面所推荐的文章,都是基于此基础上保证能理解的,没有高深的数学公式。

什么是神经网络?什么是深度学习?

为了让计算机能识别出一张照片是小狗还是小猫,我们得准备10000张照片给它学,但是计算机只认识数字,所以我们需要把照片的每一个像素点色值转换成数字,最终100*100像素的照片被转换为一个二维矩阵,通过矩阵相乘使得输入向量空间多次变换,从而能找到非线性的关系。
神经网络的本质就是一个y=f(x)的函数,x就是照片,y就是小狗,训练就是通过算法不断的反复调用调整样本参数,最终找到一个损失值(loss)最小的拟合函数,深度学习就是一个多层的神经网络。

!! 必看 !! 《从神经元到深度学习》:非常简单易懂的描述了神经网络与深度学习的发展历史,一字不落地通读两遍会让你对神经网络有一个初步的认知。

《AiLearning》这是一个系列教程,从python基础到机器学习的分类,什么是监督学习非监督学习,什么是回归分类问题,里面还包含了卷积神经网络(CNN)、循环神经网络(RNN)、长短时序网络(LSTM)等高阶模型的原理解析,但是这部分设计到数学公示推导,看不懂可以不看,起码能知道这些神经网络是用来干嘛的,以及它们相较于普通的多层神经网络的优点在哪。后面我们使用tensorflow进行模型开发的时候这些已经都有相应的封装。

深度学习在工程上的运用

  • 方案1:目前最为广泛的实现方式。算法测用python的深度学习框架来构造模型,依赖于底层大数据样本来训练,最后透出模型调用接口给服务端,前端需要做预测、分类的时候把内容通过接口提交给服务端,服务端调用算法,得到结果返回给前端。前端要做的就是调接口等返回。

    优势:训练样本数据量大,模型拟合更准,适用于大部分常规场景。
    劣势:涉及的服务接口层面多。

  • 方案2:算法侧训练模型不变,但是最后需要把模型转换为前端所需要的格式导出(官方提供了模型转换工具pip install tensorflowjs),省去了服务端。前端通过tensorflow.js加载已经训练好的模型,在浏览器里执行作出预测(前端通过tf.loadLayersModel加载keras模型)。
    在此方案中,也可以直接使用tensorflow.js在Node.js环境里训练模型,直接导出给前端。不管是python还是JS都是胶水语言,提供的只是上层的API,数据计算过程都是由底层C++调用GPU算力执行。

    优势:能够在离线场景进行预测(比如用户发布一段视频,在上传的等待过程就可以根据视频帧信息作智能推荐)。
    劣势:如果是非常复杂的模型,资源会比较大,需要预加载,对网络开销与浏览器内存有占用。

  • 方案3:前端直接在浏览器内通过tensorflow.js进行训练(需要浏览器支持WebGL),模型训练完成后进行预测。

    优势:充分利用端侧资源,能够根据用户提供的样本实时训练可变的模型。
    劣势:局限于样本数量、端侧GPU计算能力,不适合行复杂的高阶模型训练。

如何上手Tensorflow

理论知识基本了解后尽快进行实战是学习一门新技术的最好办法,在实战的中我们再来反向回补不足的理论知识。

Tensorflow是谷歌封装的一套机器学习所用的框架,它有多个编程语言版本。

keras是对tensorflow的又一层高级封装,简单来说使用keras API对编程能力要求基本没有了。目前keras已经集成到官方tensorflow API了,而且我们后面使用tensorflow.js的时候,直接就完全支持keras API,也意味着在python训练的模型代码,可以很便捷的改写为JS版本。

这是一个对输入图片进行识别的简单多层神经网络模型训练:

# cv.py
import tensorflow as tf
import numpy as np
from tensorflow import keras
# 获取训练数据集
fashion_mnist = keras.datasets.fashion_mnist
# 将数据集结构为训练样本数据,以及测试样本数据
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
# 数据归一化:每个图片原始二维矩阵的值为色值,我们先转换为0到1的小数,最后预测的时候再转回来
train_images = train_images / 255.0
test_images = test_images / 255.0
# 开始构建模型层
model = keras.Sequential([
    # 第一层将图片矩阵(28*28像素)展平为一位数组
    keras.layers.Flatten(input_shape=(28, 28)),
    # 第二层为隐藏层,设置128个神经元,并使用激活函数 relu 进行矩阵变换
    keras.layers.Dense(128, activation='relu'),
    # 最后一层为全连接输出层,目标为0-10每个数值的概率,因为我们原数据集中有10个类型的图片数据
    keras.layers.Dense(10)
])
# 打印层级详情信息
model.summary()
# 编译模型
model.compile(
    # 选择优化器
    optimizer='adam',
    # 选择损失函数
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    # 准确率函数
    metrics=['accuracy']
)
# 循环训练次数为10次,开始训练
model.fit(train_images, train_labels, epochs=10)
# 测试评估训练好的模型
test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=1)
# 具体到测试数据中第一条返回的预测结果
predictions = model.predict(test_images)
result = predictions[0]
# 打印预测结果
print(result)
print(np.argmax(result))

执行上面的python文件控制台会打印出模型构造、训练、测试结果的每一步:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten (Flatten)            (None, 784)               0         
_________________________________________________________________
dense (Dense)                (None, 128)               100480    
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290      
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
_________________________________________________________________
Epoch 1/10
1875/1875 [==============================] - 1s 784us/step - loss: 0.4979 - accuracy: 0.8251
Epoch 2/10
1875/1875 [==============================] - 1s 738us/step - loss: 0.3759 - accuracy: 0.8623
Epoch 3/10
1875/1875 [==============================] - 2s 820us/step - loss: 0.3392 - accuracy: 0.8766
Epoch 4/10
1875/1875 [==============================] - 1s 728us/step - loss: 0.3122 - accuracy: 0.8865
Epoch 5/10
1875/1875 [==============================] - 2s 839us/step - loss: 0.2950 - accuracy: 0.8916
Epoch 6/10
1875/1875 [==============================] - 1s 700us/step - loss: 0.2800 - accuracy: 0.8965
Epoch 7/10
1875/1875 [==============================] - 1s 636us/step - loss: 0.2696 - accuracy: 0.9011
Epoch 8/10
1875/1875 [==============================] - 1s 640us/step - loss: 0.2577 - accuracy: 0.9049
Epoch 9/10
1875/1875 [==============================] - 1s 717us/step - loss: 0.2490 - accuracy: 0.9081
Epoch 10/10
1875/1875 [==============================] - 2s 805us/step - loss: 0.2380 - accuracy: 0.9114
313/313 [==============================] - 0s 488us/step - loss: 0.3228 - accuracy: 0.8846
[-11.414778   -10.971654   -10.141903   -12.772112    -9.676536
  -1.9003754   -6.694176    -0.34978372  -7.149466     3.345558  ]
9

前面几行显示了模型的层数以及每层输出格式,然后就是训练10次的过程,倒数第三行显示了模型训练完成后用测试数据进行测试得到的损失值以及正确率。倒数第二行打印除了具体的一条数据每种类型的概率,最后得出索引为9概率最高,那么我们就看原始数据标签中9对应的是什么图片类型,这个就是计算机给出的识别结果。

基本上所有的模型训练,在使用keras API的情况下都是如此的清晰明了。只是层数和参数的设置不一样。那么问题来了,上面这么参数都该怎么传入呢?你最终会发现做深度学习编程能力并不是关键,你想用的算法模型都有现成的。你真正需要学习的是如何选择正确的模型,并且将各种参数设置为最合适的值,而这也是困难所在,它需要一定的经验积累以及对模型原理认知。因为同样的模型下,不同的神经网络层数、神经元个数、训练回归次数,都会导致结果出现欠拟合或者过拟合。这里只能说:无他,但手熟尔。

当我们仔细思考后会发现,如果图片的尺寸变大,模型的矩阵运算会指数级递增,计算将变得不可实现。这时候你就会探索到卷积神经网络(CNN)更适合用于作图像模型的建设,它的详细原理在之前的分享连接里有,在使用之前务必先了解原理,一个卷积神经网络的层数会更多(包含了卷积层和池化层),数据格式也有一维变成了三维,就像这样:

model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))

所以说我们才需要在尝试中发现问题,再寻找解决方案。看完整本理论书籍再开始实践是非常糟糕的选择,一来你不知道途中会遇到哪些问题,二来越来越深入的知识点会让你提前放弃。

更多像这种高阶神经网络模型可以在入门后再去慢慢了解,在此过程中可以参考 Tensorflow中文文档

使用Javascript训练、调用模型

本质上和python的tensorflow.kearas没有区别,只是python语法换成了js而已,比如构建一个包含两个隐藏层的多层神经网络:

model.js
import * as tf from '@tensorflow/tfjs';

function tf_model() {
  const model = tf.sequential();
  model.add(
    tf.layers.dense({
      units: 32, inputShape: [784]
    })
  );
  model.add(
    tf.layers.dense({
      units: 256
    })
  );
  model.add(
    tf.layers.dense({
      units: 10, 
      kernelInitializer: 'varianceScaling', 
      activation: 'softmax'
    })
  );
  return model;
}

除此之外,我们还能加载训练好的远程的模型文件,或者将训练的模型保存在本地indexDB里,以及在node.js中使用CUDA计算能力。更多的API可参照Tensorflow.js中文文档,关于API调用这对于前端来讲不是问题。

知乎有个大佬写的专栏《Tensorflow.js》系列是我目前发现的比较棒的实践案例,从最基本的机器学习模型到复杂的LSTM时序预测都有代码讲解。

总结

本文重点在于给想入门人工智能的前端工程师一些学习路线,与相关的资源推荐,并没有详细的教授深度学习的细节或者代码实现等。一来社区本身有很多已有的优秀教学文章;二来我水平有限教授不了。
其次关于深度学习在前端领域的应用场景也是值得思考的一个点,但是换个角度来想,一个没有被广泛使用的技术就意味着机会与创造力。

在此之前我们要努力成为合格的调包侠。

你可能感兴趣的:(前端探索深度学习指北)