经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » NumPy » 查看文章
从 Numpy+Pytorch 到 TensorFlow JS:总结和常用平替整理
来源:cnblogs  作者:埠默笙声声声脉  时间:2022/11/23 18:51:16  对本文有异议

demo展示

这是一个剪刀石头布预测模型,会根据最近20局的历史数据训练模型,神经网络输入为最近2局的历史数据。

如何拥有较为平滑的移植体验?

一些碎碎念

  • JavaScript 不存在像 numpy 之于 python 一样著名且好用的数据处理库,所以请放弃对 JavaScript 原生类型 Array 进行操作的尝试,转而寻找基于 TensorFlow JS API 的解决方法。
  • JavaScript 作为一门前端语言,一大特色是包含了大量异步编程(即代码不是顺序执行的,浏览器自有一套标准去调整代码的执行顺序),这是为了保证前端页面不被卡死,所必备的性质。也因此,TensorFlow JS的函数中,许多输入输出传递的都不是数据,而是Promise对象。很多功能支持异步,但如果没有完全搞懂异步编程,不妨多用同步的思路:用 tf.Tensor.arraySync() 把 Tensor 的值取出,具体来说是将 Tensor 对象以同步的方式(即立即执行)拷贝生成出一个新的 array 对象。
  • Promise 对象是ES6新增的对象,一般与then一起使用,但掌握 async & await 就够了,这是更简洁的写法。
  • 多关注 API 文档中对象方法的返回类型,返回 Promise 对象则与异步编程相关,如果要获取Promise对象储存的值,需要在有 async function 包裹的代码中前置 await 关键字。
  • Pytorch 中的张量可以通过索引访问其元素,而 TensorFlow JS 则不能,需要转换为 array 进行访问。

常用平替整理

将张量转换为数组

  • Python, Pytorch:
  1. tensor = torch.tensor([1,2,3])
  2. np_array = tensor.numpy()
  • JS, tfjs:
  1. // 方式一:arraySync()
  2. let tensor = tf.tensor1d([1,2,3]);
  3. let array = tensor.arraySync();
  4. console.log(array); // [1,2,3]
  5.  
  6. // 方式二:在async函数体内操作
  7. async function fun() {
  8. let tensor = tf.tensor1d([1,2,3]);
  9. let array = await tensor.array();
  10. console.log(array); // [1,2,3]
  11. }
  12. fun();
  13. // 注意,下面的写法是不行的,因为async函数的返回值是Promise对象
  14. array = async function (){
  15. return await tensor.array();
  16. }();
  17. console.log(array); // Promise object
  18.  
  19. // 方式三:用then取出async函数返回Promise对象中的值
  20. let a
  21. (async function() {
  22. let array = await tensor.array();
  23. return array
  24. })().then(data => {a = data;})
  25. console.log(a); // [1,2,3]

访问张量中的元素

  • Python,Pytorch:
  1. tensor = torch.tensor([1,2,3])
  2. print(tensor[0])
  3. print(tensor[-1])
  • JS,tfjs(不能直接通过访问tensor,需要转换成array):
  1. const tensor = tf.tensor1d([1,2,3]);
  2. const array = tensor.arraySync();
  3. console.log(array[0]);
    console.log(array[array.length - 1]);

获取字典/对象的关键字

  • Python:
  1. actions = {'up':[1,0,0,0], 'down':[0,1,0,0], 'left':[0,0,1,0], 'right':[0,0,0,1]}
  2. actions_keys_list = list(actions.keys())
  • JS:
  1. const actions = {'up':[1,0,0,0], 'down':[0,1,0,0], 'left':[0,0,1,0], 'right':[0,0,0,1]};
  2. const actionsKeysArray = Object.keys(actions);

“先进先出”栈

  • Python:
  1. memory = [1,2,3]
  2. memory.append(4) # 入栈
  3. memory.pop(0) # 出栈
  • JS:
  1. let memory = [1,2,3];
  2. memory.push(4); // 入栈
  3. memory.splice(0,1); // 出栈

“后进先出”栈

  • Python:
  1. memory = [1,2,3]
  2. memory.append(4) # 入栈
  3. memory.pop() # 出栈
  • JS:
  1. let memory = [1,2,3];
  2. memory.push(4); // 入栈
  3. memory.pop(); // 出栈

根据概率分布采样元素

  • Python,Numpy:
  1. actions = ['up','down','left','right']
  2. prob = [0.1, 0.4, 0.4, 0.1]
  3. sample_action = np.random.choice(actions, p=prob))
  • JS,tfjs:
  1. const actions = ['up', 'down', 'left', 'right'];
  2. const prob = [0.1, 0.4, 0.4, 0.1];
  3. sampleActionIndex = tf.multinomial(prob, 1, null, true).arraySync(); // tf.Tensor 不能作为索引,需要用 arraySync() 同步地传输为 array
  4. sampleAction = actions[sampleActionIndex];

找到数组中最大值的索引(Argmax)

  • Python,Numpy,Pyorch:
  1. actions = ['up', 'down', 'left', 'right']
  2. prob = [0.1, 0.3, 0.5, 0.1]
  3. prob_tensor = torch.tensor(prob)
  4. action_max_prob = actions[np.array(prob).argmax()] # np.array 可以作为索引
  5. action_max_prob = actions[prob_tensor.argmax().numpy()] # torch.tensor 不能作为索引,需要转换为 np.array
  • JS, tfjs:
  1. const actions = ['up', 'down', 'left', 'right'];
  2. const prob = [0.1, 0.3, 0.5, 0.1];
  3. const probTensor = tf.tensor1d(prob);
  4. const actionsMaxProb = actions[probTensor.argmax().arraySync()]; // tf.Tensor 不能作为索引,需要用 arraySync()同步地传输为 array

生成等差数列数组

  • Python:
  1. range_list = list(range(1,10,1))
  • JS, tfjs:
  1. const rangeArray = tf.range(1, 10, 1).arraySync();

打乱数组

  • Python:
  1. actions = ['up', 'down', 'left', 'right']
  2. print(random.shuffle(actions))
  • tfjs:(1)用 tf.util 类操作,处理常规的需求。
  1. const actions = ['up', 'down', 'left', 'right'];
    tf.util.shuffle(actions);
    console.log(actions);

 (2)用 tf.data.shuffle 操作,不建议,该类及其方法一般仅与 神经网络模型更新 绑定使用。

 极简逻辑回归

  • Python,Numpy,Pytorch:
  1. import numpy as np
  2. import torch
  3. from torch import nn
  4. import random
  5. class Memory(object):
  6. # 向Memory输送的数据可以是list,也可以是np.array
  7. def __init__(self, size=100, batch_size=32):
  8. self.memory_size = size
  9. self.batch_size = batch_size
  10. self.main = []
  11. def save(self, data):
  12. if len(self.main) == self.memory_size:
  13. self.main.pop(0)
  14. self.main.append(data)
  15. def sample(self):
  16. samples = random.sample(self.main, self.batch_size)
  17. return map(np.array, zip(*samples))
  18. class Model(object):
  19. # Model中所有方法的输入和返回都是np.array
  20. def __init__(self, lr=0.01, device=None):
  21. self.LR = lr
  22. self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 调用GPU 若无则CPU
  23. self.network = nn.Sequential(nn.Flatten(),
  24. nn.Linear(10, 32),
  25. nn.ReLU(),
  26. nn.Linear(32, 5),
  27. nn.Softmax(dim=1)).to(self.device)
  28. self.loss = nn.CrossEntropyLoss(reduction='mean')
  29. self.optimizer = torch.optim.Adam(self.network.parameters(), lr=self.LR)
  30. def predict_nograd(self, _input):
  31. with torch.no_grad():
  32. _input = np.expand_dims(_input, axis=0)
  33. _input = torch.from_numpy(_input).float().to(self.device)
  34. _output = self.network(_input).cpu().numpy()
  35. _output = np.squeeze(_output)
  36. return _output
  37. def update(self, input_batch, target_batch):
  38. # 设置为训练模式
  39. self.network.train()
  40. _input_batch = torch.from_numpy(input_batch).float().to(self.device)
  41. _target_batch = torch.from_numpy(target_batch).float().to(self.device)
  42. self.optimizer.zero_grad()
  43. _evaluate_batch = self.network(_input_batch)
  44. batch_loss = self.loss(_evaluate_batch, _target_batch)
  45. batch_loss.backward()
  46. self.optimizer.step()
  47. batch_loss = batch_loss.item()
  48. # 设置为预测模式
  49. self.network.eval()
  50. if __name__ == '__main__':
  51. memory = Memory()
  52. model = Model()
  53. # 产生数据并输送到内存中
  54. # 假设一个5分类问题
  55. for i in range(memory.memory_size):
  56. example = np.random.randint(0,2,size=10)
  57. label = np.eye(5)[np.random.randint(0,5)]
  58. data = [example, label]
  59. memory.save(data)
  60. # 训练100次,每次从内存中随机抽取一个batch的数据
  61. for i in range(100):
  62. input_batch, target_batch = memory.sample()
  63. model.update(input_batch, target_batch)
  64. # 预测
  65. prediction = model.predict_nograd(np.random.randint(0,2,size=10))
  66. print(prediction)
  • JS,tfjs(网页应用一般不使用GPU):
  1. const Memory = {
  2. memorySize : 100,
  3. main : [],
  4. saveData : function (data) {
  5. // data = [input:array, label:array]
  6. if (this.main.length == this.memorySize) {
  7. this.main.splice(0,1);
  8. }
  9. this.main.push(data);
  10. },
  11. getMemoryTensor: function () {
  12. let inputArray = [],
  13. labelArray = [];
  14. for (let i = 0; i < this.main.length; i++) {
  15. inputArray.push(this.main[i][0])
  16. labelArray.push(this.main[i][1])
  17. }
  18. return {
  19. inputBatch: tf.tensor2d(inputArray),
  20. labelBatch: tf.tensor2d(labelArray)
  21. }
  22. }
  23. }
  24. const Model = {
  25. batchSize: 32,
  26. epoch: 200,
  27. network: tf.sequential({
  28. layers: [
  29. tf.layers.dense({inputShape: [10], units: 16, activation: 'relu'}),
  30. tf.layers.dense({units: 5, activation: 'softmax'}),
  31. ]
  32. }),
  33. compile: function () {
  34. this.network.compile({
  35. optimizer: tf.train.sgd(0.1),
  36. shuffle: true,
  37. loss: 'categoricalCrossentropy',
  38. metrics: ['accuracy']
  39. });
  40. },
  41. predict: function (input) {
  42. // input = array
  43. // Return tensor1d
  44. return this.network.predict(tf.tensor2d([input])).squeeze();
  45. },
  46. update: async function (inputBatch, labelBatch) {
  47. // inputBatch = tf.tensor2d(memorySize × 10)
  48. // labelBatch = tf.tensor2d(memorySize × 5)
  49. this.compile();
  50. await this.network.fit(inputBatch, labelBatch, {
  51. epochs: this.epoch,
  52. batchSize: this.batchSize
  53. }).then(info => {
  54. console.log('Final accuracy', info.history.acc);
  55. });
  56. }
  57. }
  58. // 假设一个5分类问题
  59. // 随机生成样例和标签,并填满内存
  60. let example, label, rnd, data;
  61. for (let i = 0; i < Memory.memorySize; i++) {
  62. example = tf.multinomial(tf.tensor1d([.5, .5]), 10).arraySync();
  63. rnd = Math.floor(Math.random()*5);
  64. label = tf.oneHot(tf.tensor1d([rnd], 'int32'), 5).squeeze().arraySync();
  65. data = [example, label];
  66. Memory.saveData(data);
  67. }
  68. // 将内存中储存的数据导出为tensor,并训练模型
  69. let {inputBatch, labelBatch} = Memory.getMemoryTensor();
  70. Model.update(inputBatch, labelBatch);

 

 

 

 

 

 

 

原文链接:https://www.cnblogs.com/wsy950409/p/16421861.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号