【发布时间】:2014-08-04 03:02:02
【问题描述】:
为了加快一些神经网络的学习速度,我尝试了一些多线程,因为对于特定的层,每个神经元的计算是相互独立的。
我使用的原始函数是一些基本的反向传播算法,用于评估网络中的增量:
δ = 导数 * Σ(权重 * 前一个 δ)
void backpropagation (Autoencoder* AE)
{
int i, j, k;
for(i = AE->numLayer-2; i >= 0; i--)
{
for(j = 0; j < AE->layer[i].size; j++)
{
register double sum = 0.0;
for(k = 0; k < AE->layer[i+1].size; k++)
{
sum += AE->layer[i+1].neuron[k].weight[j] * AE->layer[i+1].neuron[k].delta;
}
AE->layer[i].neuron[j].delta = AE->layer[i].neuron[j].derivative * sum;
}
}
}
自动编码器是包含神经网络的结构。它工作得很好,虽然有点慢,而且首先尝试这个功能似乎是个好主意。
修改后的功能如下:
void backpropagationmultithread (Autoencoder* AE, unsigned int ncore, pthread_t* pth)
{
int i, j;
unsigned int neuronpercore, extra;
sem_t semaphore;
argThread* args[ncore];
for(i = AE->numLayer-2; i >= 0; i--)
{
neuronpercore = AE->layer[i].size / ncore;
extra = neuronpercore + (AE->layer[i].size % ncore);
sem_init(&semaphore, 0, -ncore);
for(j = 0; j < ncore; j++)
{
args[j] = malloc(sizeof(argThread));
args[j]->layer = i;
args[j]->AE = AE;
args[j]->sem = &semaphore;
args[j]->startat = neuronpercore * j;
args[j]->nneurons = (j!=ncore-1)?neuronpercore:extra;
pthread_create(&pth[j], NULL, backpropagationthread, (void*)args[j]);
}
sem_wait(&semaphore);
for(j = 0; j < ncore; j++)
{
pthread_cancel(pth[j]);
}
}
}
以及新线程的功能:
void* backpropagationthread (void* arg)
{
argThread* args = (argThread*) arg;
unsigned int j,k,layer = args->layer, start = args->startat, end = args->startat + args->nneurons;
Autoencoder* AE = args->AE;
for(j = start; j < end; j++)
{
register double sum = 0.0;
for(k = 0; k < AE->layer[layer+1].size; k++)
{
sum += AE->layer[layer+1].neuron[k].weight[j] * AE->layer[layer+1].neuron[k].delta;
}
AE->layer[layer].neuron[j].delta = AE->layer[layer].neuron[j].derivative * sum;
}
sem_post(args->sem);
free(arg);
return NULL;
}
argThread 只是一个包含要传递给线程的所有参数的小结构,ncore 是 CPU 内核的数量。这个想法是将每一层分成大致相等数量的神经元,由每个线程单独处理(如果它们不是倍数,则最后一个具有所有额外的神经元)。
新函数在某种程度上确实可以工作,而且速度更快,但是在某个阈值之后不再收敛,而旧函数会收敛,我找不到它的行为会改变的原因。我是否遗漏了一些神经元或权重?
【问题讨论】:
-
好吧,我承认我在 Windows 中待了多年,最近才重新回到 pthreads,但是为什么你要向你的线程句柄发送取消请求而不是
pthread_join()-ing 他们呢? -
我不太确定线程完成后如何处理它们。我尝试删除该部分,但实际上没有任何变化。
标签: c multithreading machine-learning neural-network backpropagation