理論與概念
不看網上教程了,直接看官網的介紹。也不用keras,keras一點都不靈活,還各種bug。
直接看源碼,地址爲https://github.com/tensorflow/models/blob/master/tutorials/image/cifar10/cifar10_input.py
我的理解是這樣,首先共享變量的定義是什麼?是如何共享的?
答:變量有一個主要存儲的地方,如cpu1,而其餘的引用都是借用,而原版永遠都是在cpu1中。所以共享的方式就是有一個拷貝在cpu1中,利用with device來借用這些變量,在with device的設備裏面借用並計算。
with tf.device('/gpu:%d' % i):
# Dequeues one batch for the GPU
image_batch, label_batch = batch_queue.dequeue()
logits = cifar10.inference(images)
上面的inference裏的所有推導計算都是這樣的:
kernel = _variable_with_weight_decay('weights',
shape=[5, 5, 3, 64],
stddev=5e-2,
wd=None)
conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME')
biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0))
pre_activation = tf.nn.bias_add(conv, biases)
conv1 = tf.nn.relu(pre_activation, name=scope.name)
可以看到都是在cpu中建立變量,因此所有變量的本體都在cpu裏,gpu只是借用來計算。按照這個思路基本上就搞清楚了。
在用多gpu時,流程爲
1,先在cpu裏建立一個網絡,這些網絡的變量名字定義好。
2,用with device gpu來借用這些變量並計算,計算的結果也存到cpu。
3,更新cpu中的權重
4,重複2
實踐與驗證
寫一個最簡單的網絡,然後用cpu存參數,用多個gpu來借用參數並計算。
def _variable_on_cpu(name, shape, initializer): """Helper to create a Variable stored on CPU memory. Args: name: name of the variable shape: list of ints initializer: initializer for Variable Returns: Variable Tensor """ with tf.device('/cpu:0'): var = tf.get_variable(name, shape, initializer=initializer) return var ccc = _variable_on_cpu('ccc', [2, 3, 4], tf.random_normal_initializer()) ddd=tf.get_variable_scope() ddd.reuse_variables() ccc1=_variable_on_cpu('ccc', [2, 3, 4], tf.random_normal_initializer()) init = tf.global_variables_initializer() sess = tf.Session() print(ccc==ccc1)#True
不加那個reuse_variables()會報錯。
接下來做一個驗證,即是cpu上建立本體變量,gpu借用這個變量,然後改變cpu本體變量,gpu借用這個變量,看變化。
ccc = _variable_on_cpu('ccc', tf.ones([2, 3, 4])) ddd = tf.get_variable_scope() ddd.reuse_variables() init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) with tf.device('/cpu:0'): with tf.device('/gpu:0'): ccc1=tf.get_variable('ccc') ccc2=ccc1*2 print(sess.run(ccc2)) fff=ccc.assign_add(tf.ones([2, 3, 4])) sess.run(fff) print(sess.run(ccc2))
這裏就一目瞭然了,上面的代碼說明我的猜想是正確的,接下來就是利用這個機制來搭一個模型,多gpu訓練。要注意的就是變量名字要唯一就好了,假如所有變量都是沒有要區分可以reuse和不能reuse的話,那麼就把所有變量都放到一個variable_scope,並且都設置爲reusable。