一. pytorch多卡训练的原理
原理:
(1)将模型加载到一个指定的主GPU上,然后将模型浅拷贝到其它的从GPU上;
(2)将总的batch数据等分到不同的GPU上(坑:需要先将数据加载到主GPU上);
(3)每个GPU根据自己分配到的数据进行forward计算得到loss,并通过backward得到权重梯度;
(4)主GPU将所有从GPU得到的梯度进行合并并用于更新模型的参数。
实现:
(1)模型方面
device_ids = [0, 1, 2, 3]
model = Model(input_size, output_size)
model = nn.DataParallel(model, device_ids=device_ids) #单卡没有这行代码
model = model.cuda(device_ids[1]) #指定哪块卡为主GPU,默认是0卡
(2)数据方面
for data in data_loader:
input_var = Variable(data.cuda(device_ids[1])) #默认指定用0卡先加载数据就会报错
output = model(input_var)
二. pytorch中gather和scatter_
- gather(聚合操作)
(1)函数原型:torch.gather(input, dim, index, out=None);
(2)函数功能:对于out指定位置上的值,去寻找input里面对应的索引位置,根据是index;
(3)三维数组的通项公式
out[i][j][k] = input[index[i][j][k]][j][k] # if dim = 0
out[i][j][k] = input[i][index[i][j][k]][k] # if dim = 1
out[i][j][k] = input[i][j][index[i][j][k]] # if dim = 2
- scatter_(分散操作)
(1)函数原型:Tensor.scatter_(dim, index, src)
(2)函数功能:src(或者说input)指定位置上的值,去分配给output对应索引位置,根据是index;
(3)三维数组的通项公式:
self[index[i][j][k]][j][k] = src[i][j][k] # if dim == 0
self[i][index[i][j][k]][k] = src[i][j][k] # if dim == 1
self[i][j][index[i][j][k]] = src[i][j][k] # if dim == 2
三. pytorch中torch.Tensor()和torch.tensor()的相同点和区别
- 相同点
Tensor和tensor都能用于生成新的张量
>>> a=torch.Tensor([1,2])
>>> a
tensor([1., 2.])
>>> a=torch.tensor([1,2])
>>> a
tensor([1, 2])
- 不同点
torch.Tensor()是python类,是torch.FloatTensor()的别名,使用torch.Tensor()会调用Tensor类的构造函数,生成float类型的张量;
而torch.tensor()仅仅是python的函数,函数原型是torch.tensor(data, dtype=None, device=None, requires_grad=False),其中data可以是scalar,list,tuple,numpy array等等。
然后torch.tensor会从data中的数据部分进行拷贝(而不是引用),根据原始数据类型生成相应的 torch.LongTensor、torch.FloatTensor和torch.DoubleTensor。比如:
>>> a=torch.tensor([1,2])
>>> a.type()
'torch.LongTensor'
>>> a=torch.tensor([1.,2.])
>>> a.type()
'torch.FloatTensor'
>>> a=np.zeros(2,dtype=np.float64)
>>> a=torch.tensor(a)
>>> a.type()
'torch.DoubleTensor'
四. pytorch中Variable的理解
torch.autograd.Variable是Autograd的核心类,它封装了Tensor,并整合了反向传播的相关实现。Variable包含了三个属性:
(1)data:存储了Tensor本体的数据;
(2)grad:保存了data的梯度,其本身也是个Variable,shape与data相同;
(3)grad_fn:指向Function对象,用于反向传播的梯度计算。但是在pytorch0.4之后,将Variable与Tensor整合到了一起,声明torch.tensor也包含这三个属性。
五. pytorch中backward()的理解
https://blog.csdn.net/sinat_28731575/article/details/90342082
六. tensorflow中variable和get_variable的区别
(1)variable是用来创建变量的,当两个变量的名字在同一作用域内相同时,tensorflow会自动将第二个定义的variable的名字加上"_1",则会生成新的name,如果使用在name_scope内,则会在name的前面加上name_scope名字的前缀;
(2)get_variable的功能是用来进行变量共享的,当变量不存在时,则会自动创建该变量。如果存在时,需要设置reuse=True来获取该变量,实现变量共享。需要注意的是,get_variable在variable_scope内使用才会给name加上前缀,在name_scope中使用并不会。
七. tensorflow中节点和边代表的什么
(1)节点代表着多种功能,比如说输入,变量初始化,运算,控制,输出等;
(2)边代表输入与输出之间的关系,即数据流动的方向。
八. pytorch中train和eval有什么不同
(1). model.train()——训练时候启用
启用 BatchNormalization 和 Dropout,将BatchNormalization和Dropout置为True
(2). model.eval()——验证和测试时候启用
不启用 BatchNormalization 和 Dropout,将BatchNormalization和Dropout置为False
train模式会计算梯度,eval模式不会计算梯度。
九、caffe的im2col
参考 caffe在实现卷积的时候,将kernel展开成行向量(每一行表示一个输出channel,output channel为几,就有几个行向量),将input tensor展开成列向量(im2col操作),但是是根据kernel的shape展开,(kernel能滑动多少次,就有多少列),不同的input channel被分成了很多矩阵块,但是都是“纵向放置”,然后将kernel和input tensor做矩阵乘法,得到output_channels行,output_h * output_w列的矩阵,每一行都可以展开成一张输出特征图(由于图像数据是连续存储的,只需要按行按列排满即可)。
PS:不同框架的访存机制不一样,所以会有行列相反这样的区别。python和c++的数据存储是行优先,matlab是列优先。所以,在caffe框架下,im2col是将一个小窗的值展开为一行,而在matlab中则展开为列。所以说,行列的问题没有本质区别,目的都是为了在计算时读取连续的内存。
十. tensorflow底层实现卷积的方式
参考 pytorch,tensorflow,caffe底层实现卷积的核心都是im2col, 这里以tensorflow为例。
tf.nn.conv2d()函数的定义为:
conv2d(input,filter,strides,padding,use_cudnn_on_gpu=True,data_format="NHWC",dilations=[1,1,1,1],name=None)
给定 4-D input 和 filter tensors计算2-D卷积,其中input tensor 的 shape是: [B, H, W, C],filter / kernel tensor 的 shape是: [filter_height, filter_width, in_channels, out_channels]
卷积op执行方式:
- 将filter展开为一个 shape 为[filter_height * filter_width * in_channels, out_channels] 大小的2-D 矩阵。
- 从 input tensor按照每个filter位置上提取图像patches来构成一个虚拟的shape大小为[batch, out_height, out_width,filter_height * filter_width * in_channels]的tensor 。(相当于在input每个卷积核的位置上(包含了同一位值对应的不同channel)提取patches)
ps:把输入图像要经行卷积操作的这一区域展成列向量的操作通常称为im2col - 对每个patch, 右乘以 filter matrix.得到[batch, out_height, out_width,out_channels]大小的输出。(Input maps的第一列×kernels的第一行,得到输出的第一个值,Input maps的第i列×kernels的第j行,得到输出特征图第i列第 j行的值)
十一. Pytorch和tensorflow区别,底层分别是怎么实现动态图和静态图的?
【参考】
tensorflow实现反向传播:
import tensorflow as tf
weight = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
biases = tf.Variable(tf.zeros([1]))
y = weight * x_data + biases
loss = tf.reduce_mean(tf.square(y - y_data)) # 计算loss
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.05)
train_step = optimizer.minimize(loss)
init = tf.initialize_all_variables()
sess.run(init)
sess.run(train_step, feed_dict={x_data:x, y_data:y})
pytorch实现反向传播:loss.backward()