 		int i = tid / layer._W_width;
 		int j = tid % layer._W_width;
 
-		//int idx = i*layer._W_width+j;
-		//printf("l=%d, i=%d, j=%d, tid=%d, idx=%d\n", l, i, j, tid, idx);
-
-		layer._d_E_W[tid] = layer._d_E_Y[i] * network->_layers[l-1]._X[j];
-		layer._W[tid] = layer._W[tid] - network->_eta*layer._d_E_W[tid];
+		// optim 1: we don't care about _d_E_W, as it is only used in this function. Gain: ~7s/epoch
+		//layer._d_E_W[tid] = layer._d_E_Y[i] * network->_layers[l-1]._X[j];
+		layer._W[tid] = layer._W[tid] - network->_eta * layer._d_E_Y[i] * network->_layers[l-1]._X[j];
+	}
+}
+
+__global__ void gpu_propagateBackFirstDerivate_setWeight_v2(struct neural_network *network, int l, int Y_max) {
+	int tid = blockDim.x*blockIdx.x + threadIdx.x;
+	struct layer& layer = network->_layers[l];
+
+	extern __shared__ pop::F32 shared_d_E_Y[];
+	shared_d_E_Y[tid] = layer._d_E_Y[tid];
+	__syncthreads();
+
+	if (tid < layer._X_size) {
+		for (int i=0; i<Y_max; i++) {
+			layer._W[tid*layer._W_width+i] = layer._W[tid*layer._W_width+i] - network->_eta * shared_d_E_Y[i] * network->_layers[l-1]._X[tid];
+		}
 	}
 }
 

			block = (h_network->_layers[l]._X_size < MAX_NB_THREADS ? h_network->_layers[l]._X_size : MAX_NB_THREADS);
			grid = h_network->_layers[l]._X_size / MAX_NB_THREADS + (h_network->_layers[l]._X_size%MAX_NB_THREADS ? 1 : 0);
			gpu_propagateBackFirstDerivate_setXError<<<grid, block>>>(d_network, out_set, out_elt_size, idx, l);
			cudaDeviceSynchronize();
		}

		// _d_E_Y[l] = _d_E_X[l] * derived_sigmoid(_X[l])
		block = (h_network->_layers[l]._Y_size < MAX_NB_THREADS ? h_network->_layers[l]._Y_size : MAX_NB_THREADS);
		grid = h_network->_layers[l]._Y_size / MAX_NB_THREADS + (h_network->_layers[l]._Y_size%MAX_NB_THREADS ? 1 : 0);
		gpu_propagateBackFirstDerivate_setYError<<<grid, block>>>(d_network, l);
		cudaDeviceSynchronize();

		// _d_E_W[l-1] = _d_E_Y[l] * _X[l-1]
		// _W[l-1] = _W[l-1] - _eta * _d_E_W[l-1]

	block = (h_network->_layers[0]._X_size < MAX_NB_THREADS ? h_network->_layers[0]._X_size : MAX_NB_THREADS);
	grid = h_network->_layers[0]._X_size / MAX_NB_THREADS + (h_network->_layers[0]._X_size%MAX_NB_THREADS ? 1 : 0);
	gpu_propagateFront_setInput<<<grid, block>>>(d_network, in_set, in_elt_size, idx);

	cublasStatus_t	stat;
	cublasHandle_t handle;
