TensorFlow 1.x 深度学习秘籍:6~10(1)https://developer.aliyun.com/article/1426770
操作步骤
让我们从秘籍开始:
- 与往常一样,第一步是导入模块。 在这种情况下,除了通常的模块之外,我们还将导入
gym
,以便我们可以使用它提供的不同环境:
import gym import numpy as np import tensorflow as tf import matplotlib.pyplot as plt
- 接下来,我们创建一个
RlAgent
类。 该类由三种方法组成-__init__
方法初始化 NN 大小并创建计算图。 在这里,我们使用了 TensorFlow 函数tf.multinomial
来决定采取的可能措施。 该函数根据我们网络的 9 个输出神经元的 Sigmoid 值返回操作。 这样可以确保网络根据概率选择最终操作。predict
方法返回由 NN 预测的动作。get_weights
方法可帮助我们获得获胜者智能体的权重和偏置:
class RlAgent(object): def __init__(self,m,n,ini=False,W=None, b=None ): self._graph = tf.Graph() with self._graph.as_default(): self._X = tf.placeholder(tf.float32,shape=(1,m)) if ini==False: self.W = tf.Variable(tf.random_normal([m,n]), trainable=False) self.bias = tf.Variable(tf.random_normal([1,n]),trainable=False) else: self.W = W self.bias = b out = tf.nn.sigmoid(tf.matmul(self._X,self.W)+ self.bias) self._result = tf.multinomial(out,1) init = tf.global_variables_initializer() self._sess = tf.Session() self._sess.run(init) def predict(self, X): action = self._sess.run(self._result, feed_dict= {self._X: X}) return action def get_weights(self): W, b = self._sess.run([self.W, self.bias]) return W, b
- 我们定义了一些辅助函数来玩一个完整的游戏
play_one_episode
:
def play_one_episode(env, agent): obs = env.reset() img_pre = preprocess_image(obs) done = False t = 0 while not done and t < 10000: env.render() # This can be commented to speed up t += 1 action = agent.predict(img_pre) #print(t,action) obs, reward, done, info = env.step(action) img_pre = preprocess_image(obs) if done: break return t
play_multiple_episodes
函数创建智能体的一个实例,并使用该智能体进行许多游戏,并返回其平均游戏时间:
def play_multiple_episodes(env, T,ini=False, W=None, b=None): episode_lengths = np.empty(T) obs = env.reset() img_pre = preprocess_image(obs) if ini== False: agent = RlAgent(img_pre.shape[1],env.action_space.n) else: agent = RlAgent(img_pre.shape[1],env.action_space.n,ini, W, b) for i in range(T): episode_lengths[i] = play_one_episode(env, agent) avg_length = episode_lengths.mean() print("avg length:", avg_length) if ini == False: W, b = agent.get_weights() return avg_length, W, b
random_search
函数调用play_multiple_episodes
; 每次调用play_multiple_episodes
时,都会使用一组新的随机权重和偏差来实例化新智能体。 这些随机创建的 NN 智能体之一将胜过其他智能体,这将是我们最终选择的智能体:
def random_search(env): episode_lengths = [] best = 0 for t in range(10): print("Agent {} reporting".format(t)) avg_length, wts, bias = play_multiple_episodes(env, 10) episode_lengths.append(avg_length) if avg_length > best: best_wt = wts best_bias = bias best = avg_length return episode_lengths, best_wt, best_bias
- 每次执行步骤时,环境都会返回一个观察场。 该观察具有三个颜色通道。 为了将其馈送到 NN,需要对观测值进行预处理,目前,我们唯一要做的预处理是将其转换为灰度,增加对比度并将其整形为行向量:
def preprocess_image(img): img = img.mean(axis =2) # to grayscale img[img==150] = 0 # Bring about a better contrast img = (img - 128)/128 - 1 # Normalize image from -1 to 1 m,n = img.shape return img.reshape(1,m*n)
- NN 智能体一一实例化,然后选择最佳智能体。 为了提高计算效率,我们目前仅搜索 10 个智能体,每个智能体玩 10 场比赛。 玩得最长的游戏被认为是最好的:
if __name__ == '__main__': env_name = 'Breakout-v0' #env_name = 'MsPacman-v0' env = gym.make(env_name) episode_lengths, W, b = random_search(env) plt.plot(episode_lengths) plt.show() print("Final Run with best Agent") play_multiple_episodes(env,10, ini=True, W=W, b=b)
结果如下:
我们可以看到我们的随机智能体也可以平均 615.5 的长度玩游戏。 不错!
用 Q 学习平衡推车
如导言所述,我们有一个由状态s
(s ∈ S
,其中S
是所有可能状态的集合)描述的环境,可以执行动作a
(a ∈ A
,其中A
由所有可能的动作组成),从而导致主体从一种状态移动到另一种状态 。 智能体因其行为而受到奖励,智能体的目标是使奖励最大化。 在 Q 学习中,智能体通过计算最大化报酬的状态-动作组合的数量(R
)来学习要采取的动作(策略,π
)。 在选择行动时,智能体不仅要考虑现在的奖励,而且要考虑未来的折扣。
Q: S × A → R
智能体以Q
的任意初始值开头,并且随着智能体选择动作a
并获得奖励r
,它会更新状态s
(取决于过去状态s
和动作a
)和Q
值:
Q(s, a) = (1 - α) · Q(s, a) + α(r + γ · max[a']Q(s', a'))
在此,α
是学习率,γ
是折扣因子。 第一项保留Q
的旧值,第二项提供Q
值的改进估计值(它包括当前奖励和未来行动的折现奖励)。 当结果状态不理想时,这将降低Q
值,从而确保智能体在下次遇到此状态时不会选择相同的动作。 类似地,当期望结果状态时,相应的Q
值将增加。
Q 学习的最简单实现涉及维护和更新状态-作用值查找表; 表的大小将为N×M
,其中N
是所有可能状态的数量,M
是所有可能动作的数量。 对于大多数环境,此表将很大。 表越大,搜索所需的时间就越多,并且存储表所需的内存也就越多,因此这不是可行的解决方案。 在本秘籍中,我们将使用 Q 学习的 NN 实现。 在此,将神经网络用作函数逼近器来预测值函数(Q)。 NN 具有等于可能动作数的输出节点,并且它们的输出表示相应动作的值函数。
准备
我们将训练一个线性神经网络来解决'CartPole-v0'
环境。 目的是平衡手推车上的杆。 观测状态由四个连续值参数组成:推车位置[-2.4, 2.4]
,推车速度[-∞, ∞]
,极角[~-41.8º, ~41.8º]
和极限速度[-∞, ∞]
。 可以通过向左或向右推推车来实现平衡,因此动作空间由两个可能的动作组成。 您可以看到CartPole-v0
环境空间:
现在,对于 Q 学习,我们需要找到一种量化连续值观测状态的方法。 这是使用类FeatureTransform
实现的; 该类首先生成 20,000 个观察空间示例的随机样本。 随机生成的观察空间示例使用 scikit StandardScaler
类进行了标准化。 然后以不同的方差使用 scikit 的RBFSampler
来覆盖观察空间的不同部分。 FeatureTransformer
类由随机观察空间示例实例化,该示例用于使用fit_transform
函数方法训练RBFSampler
。
后来,使用transform
方法将连续观察空间转换为这种特征化表示:
class FeatureTransformer: def __init__(self, env): obs_examples = np.random.random((20000, 4)) print(obs_examples.shape) scaler = StandardScaler() scaler.fit(obs_examples) # Used to converte a state to a featurizes represenation. # We use RBF kernels with different variances to cover different parts of the space featurizer = FeatureUnion([ ("cart_position", RBFSampler(gamma=0.02, n_components=500)), ("cart_velocity", RBFSampler(gamma=1.0, n_components=500)), ("pole_angle", RBFSampler(gamma=0.5, n_components=500)), ("pole_velocity", RBFSampler(gamma=0.1, n_components=500)) ]) feature_examples = featurizer.fit_transform(scaler.transform(obs_examples)) print(feature_examples.shape) self.dimensions = feature_examples.shape[1] self.scaler = scaler self.featurizer = featurizer def transform(self, observations): scaled = self.scaler.transform(observations) return self.featurizer.transform(scaled)
操作步骤
我们按以下步骤进行:
- 第一步是导入必要的模块。 这次,除了我们通常的 TensorFlow,Numpy 和 Matplotlib,我们还将从 scikit 导入 Gym 和一些类:
import numpy as np import tensorflow as tf import gym import matplotlib.pyplot as plt from sklearn.pipeline import FeatureUnion from sklearn.preprocessing import StandardScaler from sklearn.kernel_approximation import RBFSampler
- 在 Q 学习中,我们使用 NN 作为函数逼近器来估计值函数。 我们定义一个线性
NeuralNetwork
类; NN 将把变换后的观测空间作为输入并预测估计的Q
值。 由于我们有两个可能的动作,因此我们需要两个不同的神经网络对象来获取预测的状态动作值。 该类包括训练单个 NN 和预测输出的方法:
class NeuralNetwork: def __init__(self, D): eta = 0.1 self.W = tf.Variable(tf.random_normal(shape=(D, 1)), name='w') self.X = tf.placeholder(tf.float32, shape=(None, D), name='X') self.Y = tf.placeholder(tf.float32, shape=(None,), name='Y') # make prediction and cost Y_hat = tf.reshape(tf.matmul(self.X, self.W), [-1]) err = self.Y - Y_hat cost = tf.reduce_sum(tf.pow(err,2)) # ops we want to call later self.train_op = tf.train.GradientDescentOptimizer(eta).minimize(cost) self.predict_op = Y_hat # start the session and initialize params init = tf.global_variables_initializer() self.session = tf.Session() self.session.run(init) def train(self, X, Y): self.session.run(self.train_op, feed_dict={self.X: X, self.Y: Y}) def predict(self, X): return self.session.run(self.predict_op, feed_dict={self.X: X})
- 下一个重要的类是
Agent
类,它使用NeuralNetwork
类来创建学习智能体。 实例化类创建具有两个线性 NN 的智能体,每个线性 NN 具有 2,000 个输入神经元和 1 个输出神经元。 (从本质上讲,这意味着该智能体具有 2 个神经元,每个神经元具有 2,000 个输入,因为 NN 的输入层不执行任何处理)。Agent
类具有定义为预测两个 NN 的输出并更新两个 NN 权重的方法。 此处的智能体在训练阶段使用 Epsilon 贪婪策略进行探索。 在每个步骤中,智能体程序会根据 epsilon(eps
)的值选择具有最高Q
值的操作或随机操作。 epsilon 在训练过程中经过退火处理,因此,最初,智能体会采取许多随机动作(探索),但随着训练的进行,会采取具有最大Q
值的动作(探索)。 这称为探索与开发的权衡取舍:我们允许智能体在被利用的操作过程中探索随机操作,这使智能体可以尝试新的随机操作并从中学习:
class Agent: def __init__(self, env, feature_transformer): self.env = env self.agent = [] self.feature_transformer = feature_transformer for i in range(env.action_space.n): model = NeuralNetwork(feature_transformer.dimensions) self.agent.append(model) def predict(self, s): X = self.feature_transformer.transform([s]) return np.array([m.predict(X)[0] for m in self.agent]) def update(self, s, a, G): X = self.feature_transformer.transform([s]) self.agent[a].train(X, [G]) def sample_action(self, s, eps): if np.random.random() < eps: return self.env.action_space.sample() else: return np.argmax(self.predict(s))
- 接下来,我们定义一个函数来播放一集; 它类似于我们先前使用的
play_one
函数,但现在我们使用 Q 学习来更新智能体的权重。 我们首先使用env.reset()
重置环境,然后开始游戏,直到完成游戏为止(并进行了最大迭代以确保程序结束)。 像以前一样,智能体为当前观察状态选择一个动作,并在环境上执行该动作(env.step(action)
)。 现在的区别在于,根据先前状态和采取操作后的状态,使用G = r + γ · max[a']Q(s', a')
更新 NN 权重,以便它可以预测与某个动作相对应的准确期望值。 为了获得更好的稳定性,我们修改了奖励-杆位下降时,座席会获得 -400 的奖励,否则,每一步都会获得 +1 的奖励:
def play_one(env, model, eps, gamma): obs = env.reset() done = False totalreward = 0 iters = 0 while not done and iters < 2000: action = model.sample_action(obs, eps) prev_obs = obs obs, reward, done, info = env.step(action) env.render() # Can comment it to speed up. if done: reward = -400 # update the model next = model.predict(obs) assert(len(next.shape) == 1) G = reward + gamma*np.max(next) model.update(prev_obs, action, G) if reward == 1: totalreward += reward iters += 1
- 现在所有函数和类均已就绪,我们定义了智能体和环境(在本例中为
'CartPole-v0'
)。 该智能体总共播放 1000 集,并通过使用值函数与环境交互来学习:
if __name__ == '__main__': env_name = 'CartPole-v0' env = gym.make(env_name) ft = FeatureTransformer(env) agent = Agent(env, ft) gamma = 0.97 N = 1000 totalrewards = np.empty(N) running_avg = np.empty(N) for n in range(N): eps = 1.0 / np.sqrt(n + 1) totalreward = play_one(env, agent, eps, gamma) totalrewards[n] = totalreward running_avg[n] = totalrewards[max(0, n - 100):(n + 1)].mean() if n % 100 == 0: print("episode: {0}, total reward: {1} eps: {2} avg reward (last 100): {3}".format(n, totalreward, eps, running_avg[n]), ) print("avg reward for last 100 episodes:", totalrewards[-100:].mean()) print("total steps:", totalrewards.sum()) plt.plot(totalrewards) plt.xlabel('episodes') plt.ylabel('Total Rewards') plt.show() plt.plot(running_avg) plt.xlabel('episodes') plt.ylabel('Running Average') plt.show() env.close()
- 以下是智能体通过游戏获悉的总奖励和移动平均奖励的图。 根据 Cart-Pole Wiki 的说法,奖励 200 分表示该特工在接受 1,000 次训练后赢得了该剧集。 我们的特工播放 100 集时平均获得 195.7 的平均奖励,这是一项了不起的壮举:
更多
可以使用相同的逻辑为 OpenAI 的其他环境创建智能体。 但是,对于诸如 Breakout 或 Pac-Man 之类的 Atari 游戏,观察空间并不只是由四个数字组成的数组。 相反,它非常大(210×160 = 33,600 像素,具有 3 个 RGB 值); 如果没有某种形式的量化,则这种简单的 NN 可能的状态是无限的,并且不会产生良好的结果。 我们将在深度 Q 学习秘籍中使用 CNN 解决此问题。
另见
尽管有很多有关 Q 学习的 Web 链接,但一些有用的链接如下:
- https://zh.wikipedia.org/wiki/Q-Learning
- http://mnemstudio.org/path-finding-q-learning-tutorial.htm
- http://artint.info/html/ArtInt_265.html
- https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0
深度 Q 网络和 Atari 游戏
深度 Q 网络(DQN)是 Q 学习与卷积神经网络(CNN)的结合。 由 Mnih 等人在 2013 年提出。 CNN 网络具有提取空间信息的能力,因此能够从原始像素数据中学习成功的控制策略。 我们已经在第 4 章,“卷积神经网络”中使用了 CNN,因此我们直接从这里开始。
此秘籍基于 DeepMind 的原始 DQN 论文《使用深度强化学习玩 Atari》。 在本文中,他们使用了一种称为“经验重放”的概念,该概念涉及随机采样先前的游戏动作(状态,动作奖励,下一状态)。位于前脑底部的核称为“基底神经节”, 根据神经科学,它们负责选择动作,即帮助我们确定在任何给定时间执行几种可能动作中的哪一种。
准备
如先前的秘籍所述,“用 Q 学习平衡 CartPole”,对于像《吃豆人》或 Breakout 之类的 Atari 游戏,我们需要预处理观察状态空间,该状态空间由 33,600 个像素组成,具有 3 个 RGB 值。 这些像素中的每个像素都可以采用 0 到 255 之间的任何值。我们的preprocess
函数应该能够量化像素的可能值,同时减少观察状态空间。
我们利用 Scipy 的imresize
函数对图像进行下采样。 以下函数preprocess
在将图像馈送到 DQN 之前:
def preprocess(img): img_temp = img[31:195] # Choose the important area of the image img_temp = img_temp.mean(axis=2) # Convert to Grayscale# # Downsample image using nearest neighbour interpolation img_temp = imresize(img_temp, size=(IM_SIZE, IM_SIZE), interp='nearest') return img_temp
IM_SIZE
是一个全局参数-在代码中,我们将其值为 80。该函数具有描述每个过程的注释。 在这里,您可以看到预处理前后的观察空间:
要注意的另一重要事项是,当前的观察空间不能完全显示游戏情况。 例如,参见上图,您无法确定桨叶是向左还是向右移动。 因此,为了完全理解游戏的当前状态,我们需要考虑动作和观察的顺序。 在秘籍中,我们考虑了四个动作和观察序列,以确定当前情况并训练智能体。 这是借助state_update
函数完成的,该函数将当前的观察状态附加到先前的状态,从而生成一系列状态:
def update_state(state, obs): obs_small = preprocess(obs) return np.append(state[1:], np.expand_dims(obs_small, 0), axis=0)
最后,为了解决训练时的稳定性问题,我们使用了target_network
的概念,它是 DQN 的副本,但更新频率不高。 我们使用目标网络来生成 DQN 网络的目标值函数,而 DQN 在每个步骤/片段都进行更新,并且target_network
在固定间隔后进行更新(与 DQN 相同)。 由于所有更新都在 TensorFlow 会话中进行,因此我们使用名称范围来区分target_network
和 DQN 网络。
操作步骤
- 我们导入必要的模块。 我们正在使用
sys
模块的stdout.flush()
来帮助我们强制 Python 刷新标准输出(在我们的情况下为计算机监视器)中的数据。random
模块用于从经验重放缓冲区(我们存储过去经验的缓冲区)中获取随机样本。datetime
模块用于跟踪训练时间:
import gym import sys import random import numpy as np import tensorflow as tf import matplotlib.pyplot as plt from datetime import datetime from scipy.misc import imresize
- 我们定义训练的超参数; 您可以通过更改它们进行试验。 这些参数定义了经验重放缓冲区的最小和最大大小以及更新目标网络之后的情节数量:
MAX_EXPERIENCES = 500000 MIN_EXPERIENCES = 50000 TARGET_UPDATE_PERIOD = 10000 IM_SIZE = 80 K = 4
- 定义了类
DQN
; 其构造器使用tf.contrib.layers.conv2d
函数构建 CNN 网络,并定义成本和训练操作:
class DQN: def __init__(self, K, scope, save_path= 'models/atari.ckpt'): self.K = K self.scope = scope self.save_path = save_path with tf.variable_scope(scope): # inputs and targets self.X = tf.placeholder(tf.float32, shape=(None, 4, IM_SIZE, IM_SIZE), name='X') # tensorflow convolution needs the order to be: # (num_samples, height, width, "color") # so we need to tranpose later self.G = tf.placeholder(tf.float32, shape=(None,), name='G') self.actions = tf.placeholder(tf.int32, shape=(None,), name='actions') # calculate output and cost # convolutional layers Z = self.X / 255.0 Z = tf.transpose(Z, [0, 2, 3, 1]) cnn1 = tf.contrib.layers.conv2d(Z, 32, 8, 4, activation_fn=tf.nn.relu) cnn2 = tf.contrib.layers.conv2d(cnn1, 64, 4, 2, activation_fn=tf.nn.relu) cnn3 = tf.contrib.layers.conv2d(cnn2, 64, 3, 1, activation_fn=tf.nn.relu) # fully connected layers fc0 = tf.contrib.layers.flatten(cnn3) fc1 = tf.contrib.layers.fully_connected(fc0, 512) # final output layer self.predict_op = tf.contrib.layers.fully_connected(fc1, K) selected_action_values = tf.reduce_sum(self.predict_op * tf.one_hot(self.actions, K), reduction_indices=[1] ) self.cost = tf.reduce_mean(tf.square(self.G - selected_action_values)) self.train_op = tf.train.RMSPropOptimizer(0.00025, 0.99, 0.0, 1e-6).minimize(self.cost)
- 该类具有设置会话
set_session()
,预测动作值函数predict()
,更新网络update()
以及使用 Epsilon 贪婪算法sample_action()
选择动作的方法:
def set_session(self, session): self.session = session def predict(self, states): return self.session.run(self.predict_op, feed_dict={self.X: states}) def update(self, states, actions, targets): c, _ = self.session.run( [self.cost, self.train_op], feed_dict={ self.X: states, self.G: targets, self.actions: actions } ) return c def sample_action(self, x, eps): """Implements epsilon greedy algorithm""" if np.random.random() < eps: return np.random.choice(self.K) else: return np.argmax(self.predict([x])[0])
- 我们还定义了加载和保存网络的方法,因为训练可能会花费一些时间:
def load(self): self.saver = tf.train.Saver(tf.global_variables()) load_was_success = True try: save_dir = '/'.join(self.save_path.split('/')[:-1]) ckpt = tf.train.get_checkpoint_state(save_dir) load_path = ckpt.model_checkpoint_path self.saver.restore(self.session, load_path) except: print("no saved model to load. starting new session") load_was_success = False else: print("loaded model: {}".format(load_path)) saver = tf.train.Saver(tf.global_variables()) episode_number = int(load_path.split('-')[-1]) def save(self, n): self.saver.save(self.session, self.save_path, global_step=n) print("SAVED MODEL #{}".format(n))
- 将主 DQN 网络的参数复制到目标网络的方法如下:
def copy_from(self, other): mine = [t for t in tf.trainable_variables() if t.name.startswith(self.scope)] mine = sorted(mine, key=lambda v: v.name) others = [t for t in tf.trainable_variables() if t.name.startswith(other.scope)] others = sorted(others, key=lambda v: v.name) ops = [] for p, q in zip(mine, others): actual = self.session.run(q) op = p.assign(actual) ops.append(op) self.session.run(ops)
- 我们定义一个函数
learn()
,它预测值函数并更新原始 DQN 网络:
def learn(model, target_model, experience_replay_buffer, gamma, batch_size): # Sample experiences samples = random.sample(experience_replay_buffer, batch_size) states, actions, rewards, next_states, dones = map(np.array, zip(*samples)) # Calculate targets next_Qs = target_model.predict(next_states) next_Q = np.amax(next_Qs, axis=1) targets = rewards + np.invert(dones).astype(np.float32) * gamma * next_Q # Update model loss = model.update(states, actions, targets) return loss
- 既然我们已经在主代码中定义了所有特征,我们就可以使用它们来构建和训练 DQN 网络以玩 Atari 游戏。 该代码经过了很好的注释,并且是对先前 Q 学习代码的扩展,并增加了经验重放缓冲区,因此您应该不难理解它:
if __name__ == '__main__': # hyperparameters gamma = 0.99 batch_sz = 32 num_episodes = 500 total_t = 0 experience_replay_buffer = [] episode_rewards = np.zeros(num_episodes) last_100_avgs = [] # epsilon for Epsilon Greedy Algorithm epsilon = 1.0 epsilon_min = 0.1 epsilon_change = (epsilon - epsilon_min) / 500000 # Create Atari Environment env = gym.envs.make("Breakout-v0") # Create original and target Networks model = DQN(K=K, gamma=gamma, scope="model") target_model = DQN(K=K, gamma=gamma, scope="target_model") with tf.Session() as sess: model.set_session(sess) target_model.set_session(sess) sess.run(tf.global_variables_initializer()) model.load() print("Filling experience replay buffer...") obs = env.reset() obs_small = preprocess(obs) state = np.stack([obs_small] * 4, axis=0) # Fill experience replay buffer for i in range(MIN_EXPERIENCES): action = np.random.randint(0,K) obs, reward, done, _ = env.step(action) next_state = update_state(state, obs) experience_replay_buffer.append((state, action, reward, next_state, done)) if done: obs = env.reset() obs_small = preprocess(obs) state = np.stack([obs_small] * 4, axis=0) else: state = next_state # Play a number of episodes and learn for i in range(num_episodes): t0 = datetime.now() # Reset the environment obs = env.reset() obs_small = preprocess(obs) state = np.stack([obs_small] * 4, axis=0) assert (state.shape == (4, 80, 80)) loss = None total_time_training = 0 num_steps_in_episode = 0 episode_reward = 0 done = False while not done: # Update target network if total_t % TARGET_UPDATE_PERIOD == 0: target_model.copy_from(model) print("Copied model parameters to target network. total_t = %s, period = %s" % ( total_t, TARGET_UPDATE_PERIOD)) # Take action action = model.sample_action(state, epsilon) obs, reward, done, _ = env.step(action) obs_small = preprocess(obs) next_state = np.append(state[1:], np.expand_dims(obs_small, 0), axis=0) episode_reward += reward # Remove oldest experience if replay buffer is full if len(experience_replay_buffer) == MAX_EXPERIENCES: experience_replay_buffer.pop(0) # Save the recent experience experience_replay_buffer.append((state, action, reward, next_state, done)) # Train the model and keep measure of time t0_2 = datetime.now() loss = learn(model, target_model, experience_replay_buffer, gamma, batch_sz) dt = datetime.now() - t0_2 total_time_training += dt.total_seconds() num_steps_in_episode += 1 state = next_state total_t += 1 epsilon = max(epsilon - epsilon_change, epsilon_min) duration = datetime.now() - t0 episode_rewards[i] = episode_reward time_per_step = total_time_training / num_steps_in_episode last_100_avg = episode_rewards[max(0, i - 100):i + 1].mean() last_100_avgs.append(last_100_avg) print("Episode:", i,"Duration:", duration, "Num steps:", num_steps_in_episode, "Reward:", episode_reward, "Training time per step:", "%.3f" % time_per_step, "Avg Reward (Last 100):", "%.3f" % last_100_avg,"Epsilon:", "%.3f" % epsilon) if i % 50 == 0: model.save(i) sys.stdout.flush() #Plots plt.plot(last_100_avgs) plt.xlabel('episodes') plt.ylabel('Average Rewards') plt.show() env.close()
从上图中我们可以看到,特工通过训练获得了更高的报酬,并且通过每 100 集的平均报酬图可以清楚地看到情况:
这只是在训练的前 500 集之后; 为了获得更好的效果,您将需要训练更长的时间,约 10,000 集。
更多
训练智能体需要花费很多时间,这既浪费时间又消耗内存。 OpenAI Gym 提供了一个包装器来将游戏另存为视频,因此,除了使用渲染之外,您还可以使用包装器来保存视频并随后监视智能体的学习方式。 AI 工程师和发烧友可以上传这些视频以显示结果。 为此,我们需要首先导入包装器,然后创建环境,最后使用监视器。 默认情况下,它将存储 1、8、27、64 等视频,然后每第 1000 集(带有完美立方体的情节编号)存储; 默认情况下,每项训练都保存在一个文件夹中。 为此要添加的代码如下:
import gym from gym import wrappers env = gym.make('Breakout-v0) env = wrappers.Monitor(env, '/save-path')
如果您想在下一个训练中使用相同的文件夹,可以将force=True
添加到监视器。
另见
Mnih, Volodymyr, and others, Playing Atari with deep reinforcement learning, arXiv preprint arXiv:1312.5602 (2013) (https://arxiv.org/pdf/1312.5602.pdf)
Mnih, Volodymyr, et al. Human-level control through deep reinforcement learning, Nature 518.7540 (2015): 529-533
- 玩 Atari 的 DQN 的一个很酷的实现
使用策略梯度玩 Pong 游戏
到目前为止,策略梯度是最常用的 RL 算法之一。 研究表明,经过适当调优后,它们的表现要优于 DQN,同时不会遭受过多的内存和计算缺点。 与 Q 学习不同,策略梯度使用参数化策略,该策略可以选择操作而不咨询值函数。 在策略梯度中,我们讨论了表现度量η(θ[p])
; 目标是最大程度地提高表现,因此根据梯度上升算法更新 NN 的权重。 但是,TensorFlow 没有maximum
优化器,因此我们使用表现梯度的负值-∇η(θ[p])
并将其最小化。
准备
Pong 的游戏是一个两人游戏,目标是将球弹回另一位玩家。 智能体可以上下移动操纵杆(是的,是标准NoOp
)。 OpenAI 环境中的一名玩家是一位体面的 AI 玩家,他知道如何很好地玩游戏。 我们的目标是使用策略梯度来训练第二个智能体。 我们的经纪人精通所玩的每款游戏。 虽然代码已构建为只能运行 500 集,但我们应该添加一条规定以将智能体状态保存在指定的检查点,并且在下一次运行时,首先加载上一个检查点。 为此,我们首先声明一个保护程序,然后使用 TensorFlow saver.save
方法保存当前的网络状态(检查点),最后从最后保存的检查点加载网络。 为完成本秘籍的部分,在“操作步骤”一节中定义的以下PolicyNetwork
类方法可以执行此工作:
def load(self): self.saver = tf.train.Saver(tf.global_variables()) load_was_success = True # yes, I'm being optimistic try: save_dir = '/'.join(self.save_path.split('/')[:-1]) ckpt = tf.train.get_checkpoint_state(save_dir) load_path = ckpt.model_checkpoint_path self.saver.restore(self.session, load_path) except: print("no saved model to load. starting new session") load_was_success = False else: print("loaded model: {}".format(load_path)) saver = tf.train.Saver(tf.global_variables()) episode_number = int(load_path.split('-')[-1])
为了每 50 集保存一次模型,我们使用以下方法:
def save(self): self.saver.save(self.session, self.save_path, global_step=n) print("SAVED MODEL #{}".format(n))
操作步骤
- 此秘籍的代码基于 Andrej Karpathy 博客,并且其中一部分已由 Sam Greydanus 的代码进行了改编。
- 我们有通常的导入:
import numpy as np import gym import matplotlib.pyplot as plt import tensorflow as tf
- 我们定义我们的
PolicyNetwork
类。 在类构建期间,还将初始化模型超参数。__init__
方法定义输入状态self.tf_x
的占位符; 预测作用,self.tf.y
; 相应的奖励,self.tf_epr
; 网络权重; 并预测行动值,训练和更新。 您可以看到该类构造还启动了一个交互式 TensorFlow 会话:
class PolicyNetwork(object): def __init__(self, N_SIZE, h=200, gamma=0.99, eta=1e-3, decay=0.99, save_path = 'models2/pong.ckpt' ): self.gamma = gamma self.save_path = save_path # Placeholders for passing state.... self.tf_x = tf.placeholder(dtype=tf.float32, shape=[None, N_SIZE * N_SIZE], name="tf_x") self.tf_y = tf.placeholder(dtype=tf.float32, shape=[None, n_actions], name="tf_y") self.tf_epr = tf.placeholder(dtype=tf.float32, shape=[None, 1], name="tf_epr") # Weights xavier_l1 = tf.truncated_normal_initializer(mean=0, stddev=1\. / N_SIZE, dtype=tf.float32) self.W1 = tf.get_variable("W1", [N_SIZE * N_SIZE, h], initializer=xavier_l1) xavier_l2 = tf.truncated_normal_initializer(mean=0, stddev=1\. / np.sqrt(h), dtype=tf.float32) self.W2 = tf.get_variable("W2", [h, n_actions], initializer=xavier_l2) # Build Computation # tf reward processing (need tf_discounted_epr for policy gradient wizardry) tf_discounted_epr = self.tf_discount_rewards(self.tf_epr) tf_mean, tf_variance = tf.nn.moments(tf_discounted_epr, [0], shift=None, name="reward_moments") tf_discounted_epr -= tf_mean tf_discounted_epr /= tf.sqrt(tf_variance + 1e-6) # Define Optimizer, compute and apply gradients self.tf_aprob = self.tf_policy_forward(self.tf_x) loss = tf.nn.l2_loss(self.tf_y - self.tf_aprob) optimizer = tf.train.RMSPropOptimizer(eta, decay=decay) tf_grads = optimizer.compute_gradients(loss, var_list=tf.trainable_variables(), grad_loss=tf_discounted_epr) self.train_op = optimizer.apply_gradients(tf_grads) # Initialize Variables init = tf.global_variables_initializer() self.session = tf.InteractiveSession() self.session.run(init) self.load()
- 我们定义了一种计算折现奖励的方法。 这确保智能体不仅考虑当前奖励,而且考虑未来奖励。 任意时间
t
的折现奖励为R[t] = ∑γ[k]r[t + k]
,其中总和超过k∈[0, ∞]
,并且γ
是贴现因子,值在 0 到 1 之间。在我们的代码中,我们使用了gamma = 0.99
:
def tf_discount_rewards(self, tf_r): # tf_r ~ [game_steps,1] discount_f = lambda a, v: a * self.gamma + v; tf_r_reverse = tf.scan(discount_f, tf.reverse(tf_r, [0])) tf_discounted_r = tf.reverse(tf_r_reverse, [0]) return tf_discounted_r
- 在给定输入观察状态的情况下,我们定义了
tf_policy_forward
方法来提供将桨向上移动的概率。 我们使用两层神经网络实现它。 网络获取处理过的游戏状态图像,并生成一个数字,表示将球拍向上移动的可能性。 在 TensorFlow 中,由于仅在 TensorFlow 会话中计算网络图,因此我们定义了另一种方法predict_UP
来计算概率:
def tf_policy_forward(self, x): #x ~ [1,D] h = tf.matmul(x, self.W1) h = tf.nn.relu(h) logp = tf.matmul(h, self.W2) p = tf.nn.softmax(logp) return p def predict_UP(self,x): feed = {self.tf_x: np.reshape(x, (1, -1))} aprob = self.session.run(self.tf_aprob, feed); return aprob
PolicyNetwork
智能体使用update
方法更新权重:
def update(self, feed): return self.session.run(self.train_op, feed)
- 我们定义一个辅助函数来预处理观察状态空间:
# downsampling def preprocess(I): """ prepro 210x160x3 uint8 frame into 6400 (80x80) 1D float vector """ I = I[35:195] # crop I = I[::2,::2,0] # downsample by factor of 2 I[I == 144] = 0 # erase background (background type 1) I[I == 109] = 0 # erase background (background type 2) I[I != 0] = 1 # everything else (paddles, ball) just set to 1 return I.astype(np.float).ravel()
- 其余的很简单-我们创建一个游戏环境,定义要持有的数组(状态,动作,奖励,状态),并使智能体学习大量情节(休息或连续不断),这完全取决于您的计算能力和资源)。 这里要注意的重要一点是,智能体没有按动作步骤学习。 相反,智能体使用一个情节的完整(状态,动作,奖励,状态)集来纠正其策略。 这可能会占用大量内存:
if __name__ == '__main__': # Create Game Environment env_name = "Pong-v0" env = gym.make(env_name) env = wrappers.Monitor(env, '/tmp/pong', force=True) n_actions = env.action_space.n # Number of possible actions # Initializing Game and State(t-1), action, reward, state(t) xs, rs, ys = [], [], [] obs = env.reset() prev_x = None running_reward = None running_rewards = [] reward_sum = 0 n = 0 done = False n_size = 80 num_episodes = 500 #Create Agent agent = PolicyNetwork(n_size) # training loop while not done and n< num_episodes: # Preprocess the observation cur_x = preprocess(obs) x = cur_x - prev_x if prev_x is not None else np.zeros(n_size*n_size) prev_x = cur_x #Predict the action aprob = agent.predict_UP(x) ; aprob = aprob[0,:] action = np.random.choice(n_actions, p=aprob) #print(action) label = np.zeros_like(aprob) ; label[action] = 1 # Step the environment and get new measurements obs, reward, done, info = env.step(action) env.render() reward_sum += reward # record game history xs.append(x) ; ys.append(label) ; rs.append(reward) if done: # update running reward running_reward = reward_sum if running_reward is None else running_reward * 0.99 + reward_sum * 0.01 running_rewards.append(running_reward) feed = {agent.tf_x: np.vstack(xs), agent.tf_epr: np.vstack(rs), agent.tf_y: np.vstack(ys)} agent.update(feed) # print progress console if n % 10 == 0: print ('ep {}: reward: {}, mean reward: {:3f}'.format(n, reward_sum, running_reward)) else: print ('\tep {}: reward: {}'.format(n, reward_sum)) # Start next episode and save model xs, rs, ys = [], [], [] obs = env.reset() n += 1 # the Next Episode reward_sum = 0 if n % 50 == 0: agent.save() done = False plt.plot(running_rewards) plt.xlabel('episodes') plt.ylabel('Running Averge') plt.show() env.close()
下图显示了智能体在前 500 个情节中学习时的平均运行奖励:
工作原理
权重使用 Xavier 初始化进行了初始化,这确保了我们的权重既不会太大也不会太小。 两种情况都阻碍了网络的学习。 在 Xavier 初始化中,为权重分配一个具有零均值和特定方差2/(nin+nout)
的值,其中nin
和nout
该层的输入和输出数。 要了解有关 Xavier 初始化的更多信息,请参阅 Glorot 和 Bengio 在 2009 年发表的论文。 有关详细信息,请参见“另见”部分。
更多
看到智能体第一次学习演奏的任何人都会对此感到惊讶-看起来很像人。 最初的举动总是很笨拙。 缓慢地,坐席会学习走哪条路,尽管速度很慢并且经常会错过球。 但是,随着学习的继续,智能体将成为专家。
但这与我们很不一样。 一旦学会玩游戏,我们便可以在其他任何类似情况下轻松使用该知识。 RL 智能体将无法执行此操作-即使是简单的事情(例如更改环境空间的大小)也会将其恢复为零。 迁移学习是研究人员正在研究的一种技术,它可以帮助主体在另一环境空间中的一个环境中使用它所学到的知识,也许有一天可以为真正的人工智能奠定基础。
AlphaGo Zero
最近,DeepMind 发表了有关 AlphaGo Zero(AlphaGo 的最新版本)的文章。 根据他们发布的结果,AlphaGo Zero 甚至更强大,并且是历史上最强大的围棋选手。 AlphaGo 从表格状态开始,即从空白状态开始,并且仅使用棋盘状态和与其对抗的游戏来调整神经网络并预测正确的动作。
AlphaGo Zero 使用深层神经网络,该网络将原始板表示形式(当前和历史)作为输入,并输出移动概率和值。 因此,该神经网络结合了策略网络和值网络的作用。 该网络是通过自玩游戏进行训练的,这与以前的 AlphaGo 版本不同(它们是使用监督学习进行训练的)。 在每个位置上,由神经网络指导执行蒙特卡洛树搜索(MCTS)。 通过使用 MCTS 播放每个动作的自演强化学习算法来训练神经网络。
最初,神经网络的权重是随机初始化的。 在每个迭代步骤中,都会生成许多自玩游戏。 在每个时间步,使用神经网络的先前迭代对可能的策略执行 MCTS 搜索,然后通过对搜索概率进行采样来进行移动。 重复此过程直到该特定游戏终止。 存储游戏状态,采取的策略以及游戏每个时间步骤的奖励。 并行地,根据自播放的先前迭代的所有时间步长之间均匀采样的数据训练神经网络。 调整神经网络的权重,以最小化预测值和自赢者之间的误差,并使神经网络移动概率与搜索概率的相似性最大化。
在配备 4 个 TPU 的单台机器上仅进行了 3 天的训练,AlphaGo Zero 以 100-0 击败 AlphaGo。 AlphaGo Zero 完全基于 RL。 可以在 2017 年 10 月发表于《自然》上的论文《掌握无人掌握的围棋游戏》中阅读其实现的详细信息。
另见
- https://arxiv.org/pdf/1602.01783.pdf
- http://ufal.mff.cuni.cz/~straka/courses/npfl114/2016/sutton-bookdraft2016sep.pdf
- http://karpathy.github.io/2016/05/31/rl/
Xavier Glorot and Yoshua Bengio, Understanding the difficulty of training deep feedforward neural networks, Proceedings of the Thirteenth International Conference on Artificial Intelligence and Statistics, 2010, http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf
十、移动计算
在本章中,我们将讨论在移动设备上使用深度学习的问题,并为以下内容提供一些方法:
- 安装适用于 macOS 和 Android 的 TensorFlow Mobile
- 玩转 TensorFlow 和 Android 示例
- 为 MacOS 和 iPhone 安装 TensorFlow Mobile
- 为移动设备优化 TensorFlow 图
- 转换移动设备的 TensorFlow 图
介绍
在本节中,我们将介绍移动深度学习的一些用例。 这与台式机或云深度学习的情况大不相同,在台式机或云深度学习中,GPU 和电力通常可用。 实际上,在移动设备上,保存电池非常重要,并且 GPU 经常不可用。 但是,深度学习在许多情况下可能非常有用。 让我们回顾一下:
- 图像识别:现代手机具有功能强大的摄像头,用户热衷于尝试对图像和图片产生效果。 通常,了解图片中的内容也很重要,并且有多种适用于此的预训练模型,如专用于 CNN 的章节所述。 这里给出了用于图像识别的模型的一个很好的例子。
- 对象定位:识别运动对象是一项关键操作,对于视频和图像处理是必需的。 例如,可以想象如果在图像中识别出多个人,那么相机将使用多个对焦点。 这里提供了对象本地化示例的集合。
- 光学字符识别:在许多活动(例如文本分类和推荐)中,识别手写字符都是至关重要的。 深度学习可以为开展这些活动提供根本帮助。 在专用于 CNN 的章节中,我们研究了 MNIST 识别的一些示例。 关于 MNIST 的信息也可以在这个页面中找到。
- 语音识别:语音识别是访问现代电话的常用界面。 因此,深度学习用于识别语音和口头命令。 在过去的几年中,这方面的进展令人印象深刻。
- 翻译:处理多种语言是现代多元文化世界的一部分。 手机在各种语言之间进行即时翻译的准确率越来越高,深度学习帮助打破了障碍,而这在几年前是无法想象的。 在专门针对 RNN 的一章中,我们研究了一些机器翻译示例。
- 手势识别:电话开始使用手势作为接收命令的界面。 当然,有一些模型。
- 压缩:压缩是手机的关键方面。 可以想象,在通过网络发送图像或视频之前减少空间是有益的。 同样,在本地存储在设备上之前压缩数据可能会很方便。 在所有这些情况下,深度学习都可以提供帮助。 使用 RNNS 进行压缩的模型位于这里。
TensorFlow,移动和云
如上所述,电话通常没有 GPU,因此节省电池电量非常重要。 为了减轻成本,需要将许多昂贵的计算卸载到云中。 当然,要折衷考虑各种因素,包括在移动设备上执行深度学习模型的成本,将数据移至云的成本,用于此传输的电池成本以及云计算的成本。 没有单一的解决方案,最佳策略取决于您的具体情况。
安装适用于 macOS 和 Android 的 TensorFlow Mobile
在本秘籍中,我们将学习如何为移动环境设置 TensorFlow。 我的环境是 macOS,我为 Android 开发。 但是,在以下秘籍中将描述其他配置。
准备
我们将使用 Android Studio,这是适用于 Google Android 操作系统的官方集成开发环境(IDE)。
操作步骤
我们继续按以下步骤安装适用于 macOS 和 Android 的 TensorFlow mobile:
- 从这里安装 Android Studio。
- 创建一个新的项目名称
AndroidExampleTensorflow
,如以下屏幕截图所示:
在 AndroidStudio 中创建 TensorFlow 移动应用的示例,第一步如下图所示:选择电话和表格选项:
在 AndroidStudio 中创建 TensorFlow 移动应用的示例,第二步并选择一个空活动,如下图所示:
在 AndroidStudio 中创建 TensorFlow 移动应用的示例,第三步然后自定义MainActivity
,如下图所示:
在 AndroidStudio 中创建 TensorFlow 移动应用的示例,第四步称为“基础神经节”,根据神经科学,它负责选择动作,即帮助我们确定在任何给定时间执行几个可能动作中的哪个。
- 将以下行插入
build.gradle
应用中,如以下代码所示:
// added for automatically connect to TensorFlow via maven repositories { jcenter() maven { url 'https://google.bintray.com/TensorFlow' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:26.+' compile 'com.android.support.constraint:constraint-layout:1.0.2' // added for automatically compile TensorFlow compile 'org.TensorFlow:TensorFlow-android:+' testCompile 'junit:junit:4.12' }
以下屏幕截图显示了插入的代码:
- 运行项目并获得结果:
使用 AndroidStudio 进行编译的示例,其中显示了连接的设备。
在 AndroidStudio 中创建 TensorFlow 移动应用的示例。 一个简单的Hello World
应用
工作原理
使用 Android Studio 设置 Android TensorFlow 非常简单。 您只需要在应用的build.gradle
文件中添加一些配置行,Android Studio 就会代表您执行所有操作。
更多
如果要直接从 TensorFlow 源构建,则需要安装 Bazel 和 TensorFlow。 Bazel 是一个快速,可扩展,多语言和可扩展的构建系统。 Google 内部使用了构建工具 Blaze,并将 Blaze 工具的开源部分称为 Bazel。 名称是 Blaze 的字谜。
如果您正在运行 macOS,则过程非常简单:
- 按照这个页面上的说明安装 Bazel。 对于 macOS,我们将使用 Homebrew:
/usr/bin/ruby -e "$(curl -fsSL \ https://raw.githubusercontent.com/Homebrew/install/master/install)" brew install bazel bazel version brew upgrade bazel
- 从 GitHub 克隆 TensorFlow 发行版。
git clone https://github.com/TensorFlow/TensorFlow.git
玩转 TensorFlow 和 Android 示例
在本秘籍中,我们将考虑 TensorFlow 发行版中提供的标准 Android 示例并将其安装在我们的移动设备上。
准备
TensorFlow 移动 Android 应用可在 GitHub 上的以下地址获得。 2017 年 10 月,该页面包含以下示例:
- TF 分类:使用 Google Inception 模型实时对相机帧进行分类,并在相机图像上以重叠显示顶部结果。
- TF 检测:演示使用 TensorFlow 对象检测 API 训练的 SSD-Mobilenet 模型。 这是在现代卷积目标检测器的速度/精度折衷中引入的,以实时定位和跟踪摄像机预览中的目标(来自 80 个类别)。
- TF 风格化:使用基于艺术风格的学习表示的模型将相机预览图像重新设置为许多不同艺术风格的图像。
- TF 语音:运行在音频训练教程中构建的简单语音识别模型。 监听一小部分单词,并在识别它们时在 UI 中突出显示它们。
操作步骤
我们按以下步骤进行:
- 安装包的最佳方法是使用每晚创建的预构建 APK。 将浏览器指向这里并下载
TensorFlow_demo.apk
,如以下屏幕截图所示:
- 在您的设备上安装应用。 在我的示例中,我将使用 Android Studio 中可用的 Pixel XL 仿真设备。 这是直接从 Android Studio 内部模拟的终端设备。 命令
adb devices
列出所有连接的设备。 在这种情况下,我有一个 Pixel XL 模拟器,可以安装TensorFlow_demo apk
。
adb devices List of devices attached emulator-5554 device adb install -r TensorFlow_demo.apk
安装后,仿真器将具有一组新的 TensorFlow 应用可供使用,如下图所示。
- 运行您喜欢的应用。 例如,以下图像是 TF Stylize 的示例,用于通过 Transfer Learning 将相机预览图像重新设置为多种不同艺术风格的图像:
下图是 TF 语音的示例(请记住为仿真器激活麦克风):
工作原理
如果您使用夜间构建演示和adb
工具在设备上安装 APK,则安装 Android 的 TensorFlow 示例非常容易。
为 MacOS 和 iPhone 安装 TensorFlow Mobile
在本秘籍中,我们将学习如何在移动环境中设置 TensorFlow。 我的环境是 macOS,这里的想法是为 iOS 和 iPhone 开发。
准备
我们将使用 Xcode 开发环境和 CocoaPods 来预安装 TensorFlow。 我将假定您的环境中已经安装了 Xcode。 如果没有,请从这里下载。
操作步骤
我们将按照以下步骤进行操作:
- 使用以下命令安装 CocoaPods
sudo gem install cocoapods pod setup Setting up CocoaPods master repo $ /usr/local/git/current/bin/git clone https://github.com/CocoaPods/Specs.git master --progress Cloning into 'master'... remote: Counting objects: 1602077, done. remote: Compressing objects: 100% (243/243), done. remote: Total 1602077 (delta 125), reused 172 (delta 74), pack-reused 1601747 Receiving objects: 100% (1602077/1602077), 432.12 MiB | 1.83 MiB/s, done. Resolving deltas: 100% (849517/849517), done. Checking out files: 100% (188907/188907), done.
- 使用 CocoaPods 安装 TensorFlow 发行版:
cd TensorFlow/TensorFlow/examples/ios/benchmark pod install Analyzing dependencies Downloading dependencies Installing TensorFlow-experimental (1.1.1) Generating Pods project Integrating client project [!] Please close any current Xcode sessions and use `tf_benchmark_example.xcworkspace` for this project from now on. Sending stats Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.
- 从 Inception v1 下载一些样本数据。 将标签和图文件提取到
simple
和camera
文件夹内的数据文件夹中:
mkdir -p ~/graphs curl -o ~/graphs/inception5h.zip \ https://storage.googleapis.com/download.TensorFlow.org/models/inception5h.zip \ && unzip ~/graphs/inception5h.zip -d ~/graphs/inception5h cp ~/graphs/inception5h/* TensorFlow/examples/ios/benchmark/data/ cp ~/graphs/inception5h/* TensorFlow/examples/ios/camera/data/ cp ~/graphs/inception5h/* TensorFlow/examples/ios/simple/data/
- 从中下载用作测试的图像并将其复制到基准目录:
https://upload.wikimedia.org/wikipedia/commons/5/55/Grace_Hopper.jpg
cp grace_hopper.jpg ../../benchmark/data/
Grace Hopper 的图片
- 打开以前使用的示例项目。 以下命令将打开已经可用的 TensorFlow 的 Xcode 之后,运行编译,如以下代码和图像所示:
open tf_benchmark_example.xcworkspace
- 在 iPhone 模拟器中查看结果。 根据 Inception v1 类别,将步骤 4 中使用的图像识别为军服的图像:
用于 Tensorflow 计算的 Iphone 应用示例
TensorFlow 1.x 深度学习秘籍:6~10(3)https://developer.aliyun.com/article/1426772