学习笔记TF038:实现估值网络

作者: 游戏仙缘  发布:2020-01-01

Q-Learning,学习Action对应期待值(Expected UtilityState of Qatar。壹玖玖零年,Watkins提议。收敛性,1994年,Watkins和Dayan同盟证实。学习期望价值,从脚下一步到持有继续手续,总希望获取最大价值(Q值、Value卡塔尔。Action->Q函数,最棒计谋,在各种state下,选拔Q值最高的Action。不注重景况模型。有限Marco夫决策进度(Markov Dectision ProcessState of Qatar ,Q-Learning被表明最后得以找到最优政策。

Q-Learning目标,求解函数Q(st,at卡塔尔,依据当下条件气象,猜测Action期待价值。Q-Learning锻炼模型,以(状态、行为、奖赏、下意气风发意况State of Qatar构成元组(st,at,rt+1,st+1卡塔尔国样品练习,st当前事态,at当前情状下试行action,rt+1试行Action后获取褒奖,st+1下生龙活虎情景,(当前状态,行动,奖赏,下一场所卡塔尔国。特征(st,at卡塔尔(قطر‎。学习目的(期待价值)rt+1+γ·maxaQ(st+1,a卡塔尔,当前Action获得Reward,加下一步可获得最大梦想价值,当前途象行动奖赏,加下风流罗曼蒂克情形行动最大希望价值。学习目的包涵Q-Learning函数自个儿,递归求解。下一步可获最大梦想价值乘γ(衰减全面discount factor卡塔尔,将来奖赏的学习权重。discount factor 0,模型学习不到任何现在嘉勉音信,变短视,只关怀当下补益。discount factor >= 1,算法大概不只怕消失,期待价值持续增多未有衰减(discount卡塔尔国,期待价值发散。discount factor日常比1稍小。Qnew(st,at卡塔尔国<-(1-αState of Qatar·Qold(st,at卡塔尔国+α·(rt+1+γ·maxaQ(st+1,a卡塔尔State of Qatar,Q-Learning学习进程式子。旧Q-Learning函数Qold(st,at卡塔尔(قطر‎,向学习目的(当前赢得Reward加下一步可收获最大希望价值State of Qatar,按非常的小学习速率α学习,得到新Q-Learning函数Qnew(st,at卡塔尔国。学习速率决定新收获样板新闻覆盖率前左右到新闻比率,经常设很小值,保险学习进度牢固,确认保障最终收敛性。Q-Learning必要初叶值Q0,比较高初叶值,激励模型多探求。

读书Q-Learning模型用神经网络,得到模型是估价网络。用相比较深的神经互联网,正是DQN。谷歌(Google卡塔尔DeepMind,《Nature》杂谈,《Human-level control through deep reinforcement learning》指出。DeepMind用DQN制造达到规定的规范人类专家水平玩Atari2600类别游戏Agent。

state of the art DQN Trick。第三个Trick。DQN引进卷积层。模型通过Atari游戏摄像图像领会境遇音信并学习计策。DQN须要知道选取图像,具有图像识别才具。卷积神经互联网,利用可领取空间组织消息卷积层抽出特征。卷积层提取图像中最首要对象特征传给后层做分类、回归。DQN用卷积层做加强学习练习,依照条件图像输出决策。

第一个Trick。Experience Replay。深度学习必要一大波样书,守旧Q-Learning online update方法(逐意气风发对新样品学习卡塔尔(قطر‎不切合DQN。增大样品,多个epoch训练,图像每每使用。Experience Replay,积存Agent Experience样品,每趟演练随机收取部分样板供网络学习。牢固变成学习职务,防止短视只学习最新接触样品,综合再三使用过往大量样书学习。创立积存Experience缓存buffer,储存一定量较新样板。体积满了,用新样板替换最旧样板,保险大多数样品周边概率被抽到。不替换旧样品,训练进度被抽到可能率恒久比新样品高超级多。每便需求锻炼样板,直接从buffer随机抽出一定量给DQN练习,保持样品高利用率,让模型学习到较新样板。

其四个Trick。用第2个DQN互联网帮忙练习,target DQN,帮衬总计目的Q值,提供就学指标公式里的maxaQ(st+1,a卡塔尔国。多个互联网,叁个营造学习指标,三个实际上训练,让Q-Learning锻炼目的保持安澜。深化学习 Q-Learning学习目的每一次改变,学习目的总局是模型本身输出,每便换代模型参数会诱致学习指标转移,更新往往幅度大,练习进程会特别不平稳、失控,DQN练习会深陷目的Q值与预测Q值反馈循环(陷入颠荡发散,难消失卡塔尔(قطر‎。要求安静target DQN扶持互联网总计目的Q值。target DQN,低频率、缓慢学习,输出目的Q值波动异常的小,减小训练进度影响。

第四个Trick。Double DQN。DeepMind 《Deep Reinforcement Learning with Double Q-Learning》。守旧DQN高估Action Q值,高估不均匀,引致次优Action被高估超过最优Action。target DQN 担任生成目的Q值,首发生Q(st+1,aState of Qatar,再经过maxa接受最大Q值。Double DQN,在主DQN上通过最大Q值接收Action,再得到Action在target DQN Q值。主网选拔Action,targetDQN生成Action Q值。被采纳Q值,不自然总是最大,制止被高估次优Action总是超越最优Action,招致发掘不了真正最佳Action。学习目的公式:Target=rt+1+γ·Qtarget(st+1,argmaxa(Qmain(st+1,aState of QatarState of Qatar卡塔尔(قطر‎。

第5个Trick。Dueling DQN。Google 《Dueling Network Architectures for Deep Reinforcement Learning》。Dueling DQN,Q值函数Q(st,at卡塔尔拆分,一部分静态情况意况有所价值V(st卡塔尔国,Value;另生龙活虎有个别动态选拔Action额外带来价值A(atState of Qatar,Advantage。公式,Q(st,at卡塔尔(قطر‎=V(st卡塔尔国+A(at卡塔尔。网络独家总计情状Value和筛选Action Advantage。Advantage,Action与别的Action比较,零均值。网络最终,不再直接输出Action数量Q值,输出多个Value,及Action数量 Advantage值。V值分别加到每种Advantage值上,得最后结果。让DQN学习目的更分明,假如当早先时期待价值首要由环境意况调节,Value值大,全体Advantage波动非常小;借使希望价值首要由Action决定,Value值小,Advantage波动大。分解让学习指标更安定、正确,DQN对遭受气象猜度手艺越来越强。

福寿无疆带Trick DQN。职分情形GridWorld导航类水言纟工。GridWorld包罗二个hero,4个goal,2个fire。调整hero移动,每一趟向上、下、左、右方向运动一步,多触碰goal(表彰值1卡塔尔国,避开fire(奖赏值-1卡塔尔国。游戏指标,限度步数内得到最多分数。Agent 直接通过GridWorld图像学习决定hero移动最优政策。

创立GridWorld职责遭遇。载入注重库,itertools迭代操作,scipy.misc、matplotlib.pyplot绘图,锻练时间长,os按期储存模型文件。

创建境遇内物体对象class。情况物体属性,coordinates(x,y坐标卡塔尔(قطر‎、size(尺寸卡塔尔国、intensity(亮度值卡塔尔、channel(CRUISERGB颜色通道卡塔尔、reward(嘉勉值State of Qatar、name(名称卡塔尔(قطر‎。

学习笔记TF038:实现估值网络。创建GridWorld碰着class,最初化方法只传入参数情状size。意况长、宽为输入size,境遇Action Space设4,开端化情形物体对象列表。self.reset(卡塔尔方法重新载入参数意况,获得先河observation(GridWorld图像卡塔尔国,plt.imshow显示observation。

概念蒙受reset方法。创立全数GridWorld物体,1个hero(顾客调控目的卡塔尔、4个goal(reward 1卡塔尔(قطر‎、2个fire(reward -1State of Qatar,增添到物体对象列表self.objects。self.newPosition(卡塔尔国成立物体地点,随机接收未有被攻下新岗位。物有物体size、intensity 1,hero channel 2(杏黄卡塔尔国,goal channel 1(棕黄State of Qatar,fire channel 0(玛瑙红卡塔尔国。self.renderEnv(卡塔尔绘制GridWorld图像,state。

贯彻移动英豪剧中人物方法,传入值0、1、2、3八个数字,分别表示上、下、左、右。函数依照输入操作英豪移动。若是运动该方向会导致英豪出界,不会进行任何活动。

概念newPosition方法,选取三个跟现成物体不冲突地方。itertools.product方法拿到多少个变量全体结成,创立碰到size允许持有位置集合points,获取最近具有物体地点集合currentPositions,从points去掉currentPositions,剩下可用地方。np.random.choice随机抽出三个可用地点重临。

学习笔记TF038:实现估值网络。定义checkGoal函数。检查hero是还是不是触碰goal、fire。从objects获取hero,别的物体对象放置others列表。编历others列表,如若物体和坐标与hero完全大器晚成致,判别触碰。依据触碰物体销毁,self.newPosition(卡塔尔方法在从心所欲地点再一次生成物体,重回物体reward值(goal 1,fire -1卡塔尔(قطر‎。

创设长宛size+2、颜色通道数 3 图片。最初值全1,代表全朱红。最外侧内部像素颜色值全部赋0,代表灰褐。遍历物体对象列表self.objects,设置物体亮度值。scipy.misc.imresize将图像从原始大小resize 84x84x3尺寸,平常游玩图像尺寸。

概念GridWorld遇到进行一步Action方法。输入参数Action,self.moveChart(action卡塔尔国移动hero地点,self.checkGoal(卡塔尔检验hero是或不是触碰物体,拿到reward、done标识。self.renderEnv获取情况图像state,重返state、reward、done。

调用gameEnv类早先化方法,设置size 5,创制5x5大小GridWorld处境,每一遍创制GridWorld意况随机生成。小尺寸蒙受绝对容命理术数习,大尺寸较难,练习时间更加长。

规划DQN(Deep Q-Network卡塔尔国互连网。使用卷积层,能够直接从情况原始像素学习战术。输入scalarInput,扁平化长为84x84x3=21168向量,苏醒成[-1,84,84,3]学习笔记TF038:实现估值网络。尺寸图片ImageIn。tf.contrib.layers.convolution2d创建第4个卷积层,卷积核尺寸8x8,步长4x4,输出通道数(filter数量卡塔尔(قطر‎32,padding模型VALID,bias初步化器空。用4x4增长幅度和VALID模型padding,第1层卷积输出维度20x20x32。第2层卷积尺寸4x4,步长2x2,输出通道数64,输出维度9x9x64。第3层卷积尺寸3x3,步长1x1,输出通道数64,输出维度7x7x64。第4层卷积尺寸7x7,步长1x1,输出通道数512,空间尺寸只同意在一个职位卷积,,输出维度1x1x512。

tf.split(卡塔尔,第二个卷积层输出conv4平均拆分两段,streamAC、streamVC,Dueling DQN Advantage Function(Action带给的价值卡塔尔国和Value Function(情形本身价值卡塔尔国。tf.split函数第2参数代表要拆分成几段。第3参数代表要拆分多少个维度。tf.contrib.layers.flatten将streamAC和streamVC转遍平的steamA和steamV。创设streamA和streamV线性全连接层参数AW和VW。tf.random_normal开端化权重,tf.matmul做全连接层矩阵乘法,获得self.Advantage和self.Value。Advantage针对Action,输出数量为Action数量。Value针对意况统一的,输出数量 1。Q值由Value、advantage复合成,Value加上减弱均值Advantage。Advantage减去均值操作 tf.subtract,均值总括tf.reduce_mean函数(reduce_indices 1,代表Action数量维度卡塔尔(قطر‎。最终输出Action,Q值最大Action,tf.argmax。

概念Double DQN指标Q值targetQ输入placeholder,Agent动作actions输入placeholder。计算指标Q值,action由主DQN选拔,Q值由扶持target DQN生成。计算预测Q值,scalar方式actions转onehot编码格局,主DQN生成的Qout乘以actions_onehot,得预测Q值(Qout和actions都来自己作主DQN卡塔尔国。

定义loss,tf.square、tf.reduce_mean总括targetQ和Q均方固有误差,学习速率1e-4 艾达m优化器优化预测Q值和目的Q值偏差。

实现Experience Replay策略。定义experience_buffer class。初始化定义buffer_size存款和储蓄样品最大容积,成立buffer列表。定义向经buffer添新币素方法。假设高出buffer最大容积,清空最先样品,列表末尾加多新成分。定义样品抽样格局,用random.sample(卡塔尔国函数随机收取一定数量样板。

概念84x84x3 states扁平化 1维向量函数processState,方便后边聚成堆样品。

updateTargetGraph函数,更新target DQN模型参数(主DQN用DQN class self.updateModel方法创新模型参数卡塔尔国。输入变量tfVars,TensorFlow Graph全部参数。tau,target DQN向主DQN学习的速率。函数updateTargetGraph取tfVars前二分一参数,主DQN模型参数。再令帮助targetDQN参数朝向主DQN参数前行超级小比例(tau,0.001卡塔尔,target DQN缓慢学习主DQN。训练时,目的Q值不能够在若干遍迭代间波动太大,练习特别不平稳、失控,陷入目的Q值和预测Q值反馈循环。要求安静指标Q值练习互联网,缓慢学习target DQN互联网出口目的Q值,主互联网优化指标Q值和预测Q值间loss,target DQN跟随主DQN缓慢学习。函数updateTargetGraph创立改革target DQN模型参数操作,函数updateTarget推行操作。

DQN互联网练习进度参数。batch_size,每回从experience buffer获取样板数,32。更新频率update_freq,每间距多少step实施三遍模型参数更新,4。Q值衰减周密(discount factorState of Qatarγ,0.99。startE初始推行随机Action可能率。endE最后施行随机Action可能率。anneling_steps从上马随机可能率降至最后随机可能率所需步数。num_episodes总共多少次GridWorld情状试验。pre_train_steps正式用DQN接纳Action前开展多少步随机Action测量试验。max_epLength各个episode实行多少步Action。load_model是不是读取此前演习模型。path模型储存路线。h_size是DQN互连网最后全连接层隐含节点数。tau是target DQN向主DQN学习速率。

Qnetwork类开始化mainQN和帮助targetQN。开始化全数模型参数。trainables获取具备可锻炼参数。updateTargetGraph创设校正target DQN模型参数操作。

experience_buffer成立experience replay class,设置当前随机Action可能率e,总结e每一步衰减值stepDrop。开首化储存每种episode的reward列表rList,总步数total_steps。创立模型演习保存器(Saver卡塔尔(قطر‎检查保存目录是还是不是存在。

创办暗许Session,倘诺load_model标识True,检查模型文件路线checkpoint,读取载入已封存模型。实行参数开头化操作,试行更新targetQN模型参数操作。创设GridWorld试验循环,创造种种episode内部experience_buffer,内部buffer不出席当前迭代替锻炼练,练习只行使早先episode样品。开头化境况得第七个条件音讯s,processState(卡塔尔函数扁平化。开头化暗中认可done标志d、episode内总reward值rAll、episode内步数j。

创建内层循环,每回迭代实行Action。总步数稍低于pre_train_steps,强迫用随机Action,只从随机Action学习,不加剧进程。达到pre_train_steps,保留很小概率随机筛选Action。不随机接收Action,传入当前状态s给主DQN,预测获得相应推行Action。env.step(卡塔尔(قطر‎施行一步Action,得到接下来事态s1、reward、done标志。processState对s1扁平化处理,s、a、r、s1、d传入episodeBuffer存款和储蓄。

总步数当先pre_train_steps,持续下滑随机采纳Action可能率e,直到最低值endE。每当总步数到达update_freq整数部,实行三回练习,模型参数更新。从myBuffer中sample出四个batch_size样板。锻炼样品第3列音信,下生机勃勃状态s1,传入mainQN,实施main.predict,获得主模型选取Action。s1传播援助targetQN,得到s1状态下具有Action的Q值。mainQN输出Action ,采纳targetQN输出Q,获得doubleQ。四个DQN网络把筛选Action和输出Q值七个操作分隔离,Double DQN。练习样板第2列信息,当前reward,加doubleQ乘以衰减周全γ,获得学习目的targetQ。传入当前状态s,学习目的targetQ和骨子里利用Action,试行updateTarget函数,试行targetQN模型参数更新(缓慢向mainQN学习State of Qatar。完整完结叁回练习进度。每一个step截止,累计当前那步获取reward,更新当前场馆为下一步试验做计划。要是done标识为True,直接中断episode试验。

episode内部episodeBuffer增加到myBuffer,作现在训练抽样数据集。当前episode reward增加到rList。每贰十七个episode展现平均reward值。每1000个episode或任何教练成功,保存当前模型。

起初200个episode内,完全随机Action的前10000步内,平均能够博得reward在2邻座,根底baseline。

教练最终episode输出,平均reward 22,比异常的大提高。

算算每九二十一个episode平均reward,plt.plot显示reward变化趋向。从第1000个episode初始,reward飞快提高,到第4000个episode基本达到尖峰,后边进去平台期,升高非常的小。

    import numpy as np
    import random
    import tensorflow as tf
    import os
    %matplotlib inline
    from gridworld import gameEnv
    env = gameEnv(size=5)
    class Qnetwork():
        def __init__(self,h_size):
            #The network recieves a frame from the game, flattened into an array.
            #It then resizes it and processes it through four convolutional layers.
            self.scalarInput =  tf.placeholder(shape=[None,21168],dtype=tf.float32)
            self.imageIn = tf.reshape(self.scalarInput,shape=[-1,84,84,3])
            self.conv1 = tf.contrib.layers.convolution2d( 
                inputs=self.imageIn,num_outputs=32,kernel_size=[8,8],stride=[4,4],padding='VALID', biases_initializer=None)
            self.conv2 = tf.contrib.layers.convolution2d( 
                inputs=self.conv1,num_outputs=64,kernel_size=[4,4],stride=[2,2],padding='VALID', biases_initializer=None)
            self.conv3 = tf.contrib.layers.convolution2d( 
                inputs=self.conv2,num_outputs=64,kernel_size=[3,3],stride=[1,1],padding='VALID', biases_initializer=None)
            self.conv4 = tf.contrib.layers.convolution2d( 
                inputs=self.conv3,num_outputs=512,kernel_size=[7,7],stride=[1,1],padding='VALID', biases_initializer=None)

            #We take the output from the final convolutional layer and split it into separate advantage and value streams.
            self.streamAC,self.streamVC = tf.split(self.conv4,2,3)
            self.streamA = tf.contrib.layers.flatten(self.streamAC)
            self.streamV = tf.contrib.layers.flatten(self.streamVC)
            self.AW = tf.Variable(tf.random_normal([h_size//2,env.actions]))
            self.VW = tf.Variable(tf.random_normal([h_size//2,1]))
            self.Advantage = tf.matmul(self.streamA,self.AW)
            self.Value = tf.matmul(self.streamV,self.VW)

            #Then combine them together to get our final Q-values.
            self.Qout = self.Value + tf.subtract(self.Advantage,tf.reduce_mean(self.Advantage,reduction_indices=1,keep_dims=True))
            self.predict = tf.argmax(self.Qout,1)

            #Below we obtain the loss by taking the sum of squares difference between the target and prediction Q values.
            self.targetQ = tf.placeholder(shape=[None],dtype=tf.float32)
            self.actions = tf.placeholder(shape=[None],dtype=tf.int32)
            self.actions_onehot = tf.one_hot(self.actions,env.actions,dtype=tf.float32)

            self.Q = tf.reduce_sum(tf.multiply(self.Qout, self.actions_onehot), reduction_indices=1)

            self.td_error = tf.square(self.targetQ - self.Q)
            self.loss = tf.reduce_mean(self.td_error)
            self.trainer = tf.train.AdamOptimizer(learning_rate=0.0001)
            self.updateModel = self.trainer.minimize(self.loss)

    class experience_buffer():
        def __init__(self, buffer_size = 50000):
            self.buffer = []
            self.buffer_size = buffer_size

        def add(self,experience):
            if len(self.buffer) + len(experience) >= self.buffer_size:
                self.buffer[0:(len(experience)+len(self.buffer))-self.buffer_size] = []
            self.buffer.extend(experience)

        def sample(self,size):
            return np.reshape(np.array(random.sample(self.buffer,size)),[size,5])

    def processState(states):
        return np.reshape(states,[21168])

    def updateTargetGraph(tfVars,tau):
        total_vars = len(tfVars)
        op_holder = []
        for idx,var in enumerate(tfVars[0:total_vars//2]):
            op_holder.append(tfVars[idx+total_vars//2].assign((var.value()*tau) + ((1-tau)*tfVars[idx+total_vars//2].value())))
        return op_holder
    def updateTarget(op_holder,sess):
        for op in op_holder:
            sess.run(op)
    batch_size = 32 #How many experiences to use for each training step.
    update_freq = 4 #How often to perform a training step.
    y = .99 #Discount factor on the target Q-values
    startE = 1 #Starting chance of random action
    endE = 0.1 #Final chance of random action
    anneling_steps = 10000. #How many steps of training to reduce startE to endE.
    num_episodes = 10000#How many episodes of game environment to train network with.
    pre_train_steps = 10000 #How many steps of random actions before training begins.
    max_epLength = 50 #The max allowed length of our episode.
    load_model = False #Whether to load a saved model.
    path = "./dqn" #The path to save our model to.
    h_size = 512 #The size of the final convolutional layer before splitting it into Advantage and Value streams.
    tau = 0.001 #Rate to update target network toward primary network
    tf.reset_default_graph()
    mainQN = Qnetwork(h_size)
    targetQN = Qnetwork(h_size)
    init = tf.global_variables_initializer()
    trainables = tf.trainable_variables()
    targetOps = updateTargetGraph(trainables,tau)
    myBuffer = experience_buffer()
    #Set the rate of random action decrease. 
    e = startE
    stepDrop = (startE - endE)/anneling_steps
    #create lists to contain total rewards and steps per episode
    rList = []
    total_steps = 0
    #Make a path for our model to be saved in.
    saver = tf.train.Saver()
    if not os.path.exists(path):
        os.makedirs(path)
    #%%
    with tf.Session() as sess:
        if load_model == True:
            print('Loading Model...')
            ckpt = tf.train.get_checkpoint_state(path)
            saver.restore(sess,ckpt.model_checkpoint_path)
        sess.run(init)
        updateTarget(targetOps,sess) #Set the target network to be equal to the primary network.
        for i in range(num_episodes+1):
            episodeBuffer = experience_buffer()
            #Reset environment and get first new observation
            s = env.reset()
            s = processState(s)
            d = False
            rAll = 0
            j = 0
            #The Q-Network
            while j < max_epLength: #If the agent takes longer than 200 moves to reach either of the blocks, end the trial.
                j+=1
                #Choose an action by greedily (with e chance of random action) from the Q-network
                if np.random.rand(1) < e or total_steps < pre_train_steps:
                    a = np.random.randint(0,4)
                else:
                    a = sess.run(mainQN.predict,feed_dict={mainQN.scalarInput:[s]})[0]
                s1,r,d = env.step(a)
                s1 = processState(s1)
                total_steps += 1
                episodeBuffer.add(np.reshape(np.array([s,a,r,s1,d]),[1,5])) #Save the experience to our episode buffer.

                if total_steps > pre_train_steps:
                    if e > endE:
                        e -= stepDrop

                    if total_steps % (update_freq) == 0:
                        trainBatch = myBuffer.sample(batch_size) #Get a random batch of experiences.
                        #Below we perform the Double-DQN update to the target Q-values
                        A = sess.run(mainQN.predict,feed_dict={mainQN.scalarInput:np.vstack(trainBatch[:,3])})
                        Q = sess.run(targetQN.Qout,feed_dict={targetQN.scalarInput:np.vstack(trainBatch[:,3])})
                        doubleQ = Q[range(batch_size),A]
                        targetQ = trainBatch[:,2] + y*doubleQ
                        #Update the network with our target values.
                        _ = sess.run(mainQN.updateModel, 
                            feed_dict={mainQN.scalarInput:np.vstack(trainBatch[:,0]),mainQN.targetQ:targetQ, mainQN.actions:trainBatch[:,1]})

                        updateTarget(targetOps,sess) #Set the target network to be equal to the primary network.
                rAll += r
                s = s1

                if d == True:
                    break

            #Get all experiences from this episode and discount their rewards.
            myBuffer.add(episodeBuffer.buffer)
            rList.append(rAll)
            #Periodically save the model.
            if i>0 and i % 25 == 0:
                print('episode',i,', average reward of last 25 episode',np.mean(rList[-25:]))
            if i>0 and i % 1000 == 0:
                saver.save(sess,path+'/model-'+str(i)+'.cptk')
                print("Saved Model")            
        saver.save(sess,path+'/model-'+str(i)+'.cptk')
    #%%
    rMat = np.resize(np.array(rList),[len(rList)//100,100])
    rMean = np.average(rMat,1)
    plt.plot(rMean)

 

参照他事他说加以考察资料:
《TensorFlow实战》

款待付费咨询(150元每刻钟State of Qatar,小编的Wechat:qingxingfengzi

本文由6165金沙总站发布于游戏仙缘,转载请注明出处:学习笔记TF038:实现估值网络

关键词:

上一篇:没有了
下一篇:明亮温馨的原木风 打造猫咪的游乐园