Current section

Files

Jump to
deeppipe2 lib nifs.cu
Raw

lib/nifs.cu

#include "erl_nif.h"
#include "cublas.h"
#include "stdio.h"
#include "time.h"
#define IDX2C(i,j,ld) (((j)*(ld))+(i))
#define IDX3C(c,i,j,in_h,in_w) ((c)*((in_h)*(in_w)) + (i)*(in_w) +(j))
#define IDX4C(n,c,i,j,in_c,in_h,in_w) ((n)*((in_c)*(in_h)*(in_w)) + (c)*((in_h)*(in_w)) + (i)*(in_w) +(j))
#define IDX5C(t,n,c,i,j,in_n,in_c,in_h,in_w) ((t)*((in_n)*(in_c)*(in_h)*(in_w)) + (n)*((in_c)*(in_h)*(in_w)) + (c)*((in_h)*(in_w)) + (i)*(in_w) +(j))
#define BREAK return(enif_make_int(env, 0));
#define PI 3.14159265358979323846
#define SIGMOID(x) (1 / (1+exp(-1*x)))
#define CHECK(call) \
{ \
const cudaError_t error = call; \
if (error != cudaSuccess) \
{ \
return enif_make_int(env,10000+(int)error); \
} \
}
#define CUBLAS(call) \
{ \
const cublasStatus error = call; \
if (error != CUBLAS_STATUS_SUCCESS) \
{ \
return enif_make_int(env,11000+(int)error); \
} \
}
__global__ void pooling_kernel(float *a, float *b, float *c, int st_h, int st_w, int in_c, int in_h, int in_w)
{
int bid = blockIdx.x;
int tid = threadIdx.x;
int n1,c1,h1,w1,h2,w2,in_h2,in_w2,start_h1,end_h1,start_w1,end_w1,max_h,max_w;
float max,fmax_h,fmax_w;
n1 = bid;
c1 = tid;
in_h2 = in_h / st_h;
in_w2 = in_w / st_w;
for(w2=0;w2<in_w2;w2++){
for(h2=0;h2<in_h2;h2++){
max = -999999999.0;
start_h1 = st_h*h2;
end_h1 = st_h*(h2+1);
start_w1 = st_w*w2;
end_w1 = st_w*(w2+1);
for(h1=start_h1;h1<end_h1;h1++){
for(w1=start_w1;w1<end_w1;w1++){
if(a[IDX4C(n1,c1,h1,w1,in_c,in_h,in_w)] >= max){
max = a[IDX4C(n1,c1,h1,w1,in_c,in_h,in_w)];
max_h = h1;
max_w = w1;
}
}
}
b[IDX4C(n1,c1,h2,w2,in_c,in_h2,in_w2)] = max;
fmax_h = (float)max_h;
fmax_w = (float)max_w;
c[IDX4C(n1,c1,h2,w2,in_c,in_h2,in_w2)] = fmax_h * 1000.0 + fmax_w;
}
}
}
/*
1st arg in_n of tensor
2nd arg in_c of tensor
3rd arg in_h of tensor
4th arg in_w of tensor
5th arg binary of tensor
6th arg stride
return list [ts1,ts2]
ts1 is result data for forward
ts2 is result data dor backward. this is sparse matrix
e.g.
|0.1,0.2,0.3,0.4|
|0.5,0.6,0.7,0.8|
|0.9,1.0,1.1,1.2|
|1.3,1.4,1.5,1.6|
ts1
|0.6,0.8|
|1.4,1.6|
ts2
each element is row*1000+col
|1.0*1000+1.0,1.0*1000*3.0|
|3.0*1000+1.0,3.0*1000+3.0|
*/
static ERL_NIF_TERM
pooling1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin,c_bin,tuple;
int in_n,in_c,in_h,in_w,st_h,st_w, n1, n2;
float *a,*b, *c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &st_h)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &st_w)) return enif_make_int(env,7);
n1 = in_n * in_c * in_h * in_w;
n2 = in_n * in_c * (in_h / st_h) * (in_w / st_w);
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n2 * sizeof(float), &b_bin);
c = (float *) enif_make_new_binary(env, n2 * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n2 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n2 * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n2 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n2 * sizeof(float), cudaMemcpyHostToDevice));
dim3 blocks(in_n,1,1);
dim3 threads(in_c,1,1);
pooling_kernel <<<blocks, threads>>>(dev_a, dev_b, dev_c, st_h, st_w, in_c, in_h, in_w);
// copy to host b,c from GPU dev_b,dev_c
CHECK(cudaMemcpy(b, dev_b, n2 * sizeof(float), cudaMemcpyDeviceToHost));
CHECK(cudaMemcpy(c, dev_c, n2 * sizeof(float), cudaMemcpyDeviceToHost));
// return forward data and backward data with tuple {b_bin,c_bin}
tuple = enif_make_tuple2(env,b_bin,c_bin);
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(tuple);
}
__global__ void unpooling_kernel(float *a, float *b, float *c, int st_h, int st_w, int in_c, int in_h, int in_w)
{
int bid = blockIdx.x;
int tid = threadIdx.x;
int n1,c1,h1,w1,h2,w2,start_h1,end_h1,start_w1,end_w1,max_h,max_w,in_h1,in_w1;
float loss,elt;
n1 = bid;
c1 = tid;
in_h1 = in_h * st_h;
in_w1 = in_w * st_w;
for(h2=0;h2<in_h;h2++){
for(w2=0;w2<in_w;w2++){
start_h1 = st_h*h2;
end_h1 = st_h*(h2+1);
start_w1 = st_w*w2;
end_w1 = st_w*(w2+1);
elt = a[IDX4C(n1,c1,h2,w2,in_c,in_h,in_w)];
loss = b[IDX4C(n1,c1,h2,w2,in_c,in_h,in_w)];
max_h = (int) floor(elt / 1000.0);
max_w = (int) fmodf(elt,1000.0);
for(h1=start_h1;h1<end_h1;h1++){
for(w1=start_w1;w1<end_w1;w1++){
if(h1 == max_h && w1 == max_w){
c[IDX4C(n1,c1,h1,w1,in_c,in_h1,in_w1)] = loss;
}
else{
c[IDX4C(n1,c1,h1,w1,in_c,in_h1,in_w1)] = 0.0;
}
}
}
}
}
}
/*
1st arg in_n of sparse-tensor
2nd arg in_c of sparse-tensor
3rd arg in_h of sparse-tensor
4th arg in_w of sparse-tensor
5th arg binary of sparse-tensor
6th arg binary of loss-tensor
7th arg stride
return gradiate tensor
e.g.
ts1 index-tensor
each element is row*1000+col
|1.0*1000+1.0,1.0*1000*3.0|
|3.0*1000+1.0,3.0*1000+3.0|
ts2 loss-tensor
|0.1,0.2|
|0.3,0.4|
return
|0.0,0.0,0.0,0.0|
|0.0,0.1,0.0,0.2|
|0.0,0.0,0.0,0.0|
|0.0,3.4,0.0,0.4|
*/
static ERL_NIF_TERM
unpooling1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin;
int in_n,in_c,in_h,in_w,st_h,st_w, n1, n2;
float *a,*b, *c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
if (!enif_inspect_binary(env, argv[5], &b_bin )) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &st_h)) return enif_make_int(env,7);
if (!enif_get_int(env, argv[7], &st_w)) return enif_make_int(env,8);
n1 = in_n * in_c * in_h * in_w;
n2 = in_n * in_c * (in_h * st_h) * (in_w * st_w);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n2 * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n2 * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n2 * sizeof(float), cudaMemcpyHostToDevice));
dim3 blocks(in_n,1,1);
dim3 threads(in_c,1,1);
unpooling_kernel <<<blocks, threads>>>(dev_a, dev_b, dev_c, st_h, st_w, in_c, in_h, in_w);
// copy to host d from GPU dev_d
CHECK(cudaMemcpy(c, dev_c, n2 * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
__global__ void convolute1_kernel(float *a, float *b, float *c, int filt_n, int filt_c, int filt_h, int filt_w,
int st_h, int st_w, int pad, int in_c, int in_h, int in_w, int oh, int ow)
{
int bid = blockIdx.x;
int tid = threadIdx.x;
int n1,c1,c2,h1,w1,h2,w2,start_h1,end_h1,start_w1,end_w1;
float sum,elt1,elt2;
n1 = bid;
c2 = tid;
for(w2=0;w2<ow;w2++){
for(h2=0;h2<oh;h2++){
sum = 0.0;
start_h1 = st_h*h2-pad;
end_h1 = start_h1 + filt_h;
start_w1 = st_w*w2-pad;
end_w1 = start_w1 + filt_w;
for(c1=0;c1<in_c;c1++){
for(h1=start_h1;h1<end_h1;h1++){
for(w1=start_w1;w1<end_w1;w1++){
if(h1 >= 0 && h1 < in_h && w1 >= 0 && w1 < in_w){
elt1 = a[IDX4C(n1,c1,h1,w1,in_c,in_h,in_w)];
elt2 = b[IDX4C(c2,c1,h1-start_h1,w1-start_w1,filt_c,filt_h,filt_w)];
sum = sum + elt1*elt2;
}
}
}
}
c[IDX4C(n1,c2,h2,w2,filt_n,oh,ow)] = sum;
}
}
}
/*
1st arg in_n of input tensor
2nd arg in_c of input tensor
3rd arg in_h of input tensor
4th arg in_w of input tensor
5th arg filt_n of filter tensor
6th arg filt_c of filter tensor
7th arg filt_h of filter tensor
8th arg filt_w of filter tensor
9th arg binary of input tensor
10th arg binary of filter tensor
11th arg stride
12th arg padding
*/
static ERL_NIF_TERM
convolute1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin;
int in_n,in_c,in_h,in_w, filt_n,filt_c,filt_h,filt_w, st_h,st_w,pad, n1, n2, n3, oh, ow;
float *a,*b, *c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &filt_n)) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &filt_c)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &filt_h)) return enif_make_int(env,7);
if (!enif_get_int(env, argv[7], &filt_w)) return enif_make_int(env,8);
if (!enif_inspect_binary(env, argv[8], &a_bin )) return enif_make_int(env,9);
if (!enif_inspect_binary(env, argv[9], &b_bin )) return enif_make_int(env,10);
if (!enif_get_int(env, argv[10], &st_h)) return enif_make_int(env,11);
if (!enif_get_int(env, argv[11], &st_w)) return enif_make_int(env,12);
if (!enif_get_int(env, argv[12], &pad)) return enif_make_int(env,13);
n1 = in_n * in_c * in_h * in_w;
n2 = filt_n * filt_c * filt_h * filt_w;
oh = (in_h+2*pad-filt_h)/st_h + 1;
ow = (in_w+2*pad-filt_w)/st_w + 1;
n3 = in_n * filt_n * oh * ow; // n of filter generate n channel
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n3 * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n2 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n3 * sizeof(float)));
// copy from host a,b,c to GPU dev_a, dev_b, dev_c
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n2 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n3 * sizeof(float), cudaMemcpyHostToDevice));
dim3 blocks(in_n,1,1);
dim3 threads(filt_n,1,1);
convolute1_kernel <<<blocks, threads>>>(dev_a, dev_b, dev_c, filt_n, filt_c, filt_h, filt_w, st_h, st_w, pad, in_c, in_h, in_w, oh, ow);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n3 * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
__global__ void deconvolute1_kernel(float *a, float *b, float *c, int filt_n, int filt_c, int filt_h, int filt_w,
int st_h, int st_w, int pad1, int pad, int in_c, int in_h, int in_w, int oh, int ow, int oh1, int ow1)
{
int bid = blockIdx.x;
int tid = threadIdx.x;
int n1,c1,c2,h1,w1,h2,w2,start_h1,end_h1,start_w1,end_w1;
float sum,elt1,elt2;
n1 = bid;
c2 = tid;
//full convolute. stride=1 always
for(w2=0;w2<ow;w2++){
for(h2=0;h2<oh;h2++){
start_h1 = h2-pad1;
end_h1 = start_h1 + filt_h;
start_w1 = w2-pad1;
end_w1 = start_w1 + filt_w;
sum = 0.0;
for(h1=start_h1;h1<end_h1;h1++){
for(w1=start_w1;w1<end_w1;w1++){
for(c1=0;c1<filt_n;c1++){
if(h1 >= 0 && h1 < in_h && w1 >= 0 && w1 < in_w){
elt1 = a[IDX4C(n1,c1,h1,w1,in_c,in_h,in_w)]; //loss tensor
elt2 = b[IDX4C(c1,c2,h1-start_h1,w1-start_w1,filt_c,filt_h,filt_w)]; //filter tensor
sum = sum + elt1*elt2;
}
}
}
}
if(h2-pad >=0 && h2-pad < oh1 && w2-pad >= 0 && w2-pad < ow1){
c[IDX4C(n1,c2,h2-pad,w2-pad,filt_c,oh1,ow1)] = sum;
}
}
}
}
/*
1st arg in_n of input tensor
2nd arg in_c of input tensor
3rd arg in_h of input tensor
4th arg in_w of input tensor
5th arg filt_n of filter tensor
6th arg filt_c of filter tensor
7th arg filt_h of filter tensor
8th arg filt_w of filter tensor
9th arg binary of input loss tensor
10th arg binary of filter tensor
11th arg stride hight
12th arg stride width
13th arg padding
memo
ex padding = 1
loss 4*4
filter 2*2
input 3*3 padding=1
(3-2+2*1)/1 + 1 = 4
decovolute compute 5*5(3*3 padding=1) and save result range 3*3
*/
static ERL_NIF_TERM
deconvolute1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin;
int in_n,in_c,in_h,in_w, filt_n,filt_c,filt_h,filt_w, st_h,st_w,pad, pad1, n1, n2, n3, oh, ow, oh1, ow1, i,j,k,l;
float *a,*b, *b1, *c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &filt_n)) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &filt_c)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &filt_h)) return enif_make_int(env,7);
if (!enif_get_int(env, argv[7], &filt_w)) return enif_make_int(env,8);
if (!enif_inspect_binary(env, argv[8], &a_bin )) return enif_make_int(env,9);
if (!enif_inspect_binary(env, argv[9], &b_bin )) return enif_make_int(env,10);
if (!enif_get_int(env, argv[10], &st_h)) return enif_make_int(env,11);
if (!enif_get_int(env, argv[11], &st_w)) return enif_make_int(env,12);
if (!enif_get_int(env, argv[12], &pad)) return enif_make_int(env,13);
n1 = in_n * in_c * in_h * in_w;
n2 = filt_n * filt_c * filt_h * filt_w;
pad1 = filt_h - 1;
// pad1 = filt_h -1, pad is original padding size
oh = (in_h+2*pad1-filt_h)/st_h + 1;
ow = (in_w+2*pad1-filt_w)/st_w + 1;
oh1 = (in_h+2*(pad1-pad)-filt_h)/st_h + 1;
ow1 = (in_w+2*(pad1-pad)-filt_w)/st_w + 1;
n3 = in_n * filt_c * oh1 * ow1; // channel of filter generate same channel input tensor
a = (float *) a_bin.data;
b = (float *) b_bin.data;
b1 = (float *) enif_alloc(n2 * sizeof(float));
c = (float *) enif_make_new_binary(env, n3 * sizeof(float), &c_bin);
//rotate 180 degree
for(i=0;i<filt_n;i++){
for(j=0;j<filt_c;j++){
for(k=0;k<filt_h;k++){
for(l=0;l<filt_w;l++){
b1[IDX4C(i,j,filt_h-k-1,filt_w-l-1,filt_c,filt_h,filt_w)] = b[IDX4C(i,j,k,l,filt_c,filt_h,filt_w)];
}
}
}
}
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n2 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n3 * sizeof(float)));
// copy from host a,b1,c to GPU dev_a, dev_b, dev_c
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b1, n2 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n3 * sizeof(float), cudaMemcpyHostToDevice));
dim3 blocks(in_n,1,1);
dim3 threads(filt_c,1,1);
deconvolute1_kernel <<<blocks, threads>>>(dev_a, dev_b, dev_c, filt_n, filt_c, filt_h, filt_w, st_h, st_w, pad1, pad, in_c, in_h, in_w, oh, ow, oh1, ow1);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n3 * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
enif_free(b1);
return(c_bin);
}
__global__ void deconvolute2_kernel(float *a1, float *a, float *b, float *c, int filt_n, int filt_c,int filt_h, int filt_w,
int st_h, int st_w, int pad, int in_c, int in_h, int in_w, int loss_h, int loss_w)
{
int bid = blockIdx.x;
int tid = threadIdx.x;
int n1,c1,c2,h1,w1,h2,w2,oh,ow,start_h1,end_h1,start_w1,end_w1;
int j,k,l,k1,l1;
float sum,elt1,elt2;
n1 = bid;
c2 = tid;
// caution! stride=1
oh = (in_h+2*pad-filt_h) + 1;
ow = (in_w+2*pad-filt_w) + 1;
//dilate loss tensor.
for(j=0;j<filt_n;j++){
for(k=0;k<loss_h;k++){
for(l=0;l<loss_w;l++){
elt1 = a[IDX4C(n1,j,k,l,in_c,loss_h,loss_w)];
k1 = st_h*k;
l1 = st_w*l;
a1[IDX4C(n1,j,k1,l1,in_c,in_h,in_w)] = elt1;
}
}
}
//full convulute. stride=1
for(c2=0;c2<filt_c;c2++){
for(w2=0;w2<ow;w2++){
for(h2=0;h2<oh;h2++){
start_h1 = h2-pad;
end_h1 = start_h1 + filt_h;
start_w1 = w2-pad;
end_w1 = start_w1 + filt_w;
sum = 0.0;
for(h1=start_h1;h1<end_h1;h1++){
for(w1=start_w1;w1<end_w1;w1++){
for(c1=0;c1<filt_n;c1++){
if(h1 >= 0 && h1 < in_h && w1 >= 0 && w1 < in_w){
elt1 = a1[IDX4C(n1,c1,h1,w1,in_c,in_h,in_w)]; //loss tensor
elt2 = b[IDX4C(c1,c2,h1-start_h1,w1-start_w1,filt_c,filt_h,filt_w)]; //filter tensor
sum = sum + elt1*elt2;
}
}
}
}
c[IDX4C(n1,c2,h2,w2,filt_c,oh,ow)] = sum;
}
}
}
}
/*
dilate loss tensor
e.g.
|1.0,2.0|
|3.0,4.0|
dilated stride=2
|1.0,0.0,2.0|
|0.0,0.0,0.0|
|3.0,0.0,4.0|
*/
/*
1st arg in_n of input loss tensor
2nd arg in_c of input loss tensor
3rd arg in_h of input loss tensor
4th arg in_w of input loss tensor
5th arg filt_n of filter tensor
6th arg filt_c of filter tensor
7th arg filt_h of filter tensor
8th arg filt_w of filter tensor
9th arg binary of input loss tensor
10th arg binary of filter tensor
11th arg stride hight
12th arg stride width
13th arg padding
*/
static ERL_NIF_TERM
deconvolute2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin;
int in_n,in_c,in_h,in_w,filt_n,filt_c,filt_h, filt_w, st_h, st_w,pad, pad1, n1, n2, n3, oh, ow, i,j,k,l, loss_h, loss_w;
float *a, *a1, *b, *b1, *c;
float *dev_a, *dev_a1, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &loss_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &loss_w)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &filt_n)) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &filt_c)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &filt_h)) return enif_make_int(env,7);
if (!enif_get_int(env, argv[7], &filt_w)) return enif_make_int(env,8);
if (!enif_inspect_binary(env, argv[8], &a_bin )) return enif_make_int(env,9);
if (!enif_inspect_binary(env, argv[9], &b_bin )) return enif_make_int(env,10);
if (!enif_get_int(env, argv[10], &st_h)) return enif_make_int(env,11);
if (!enif_get_int(env, argv[11], &st_w)) return enif_make_int(env,12);
if (!enif_get_int(env, argv[12], &pad)) return enif_make_int(env,13);
// size for dilate
in_h = loss_h + (loss_h - 1)*(st_h - 1);
in_w = loss_w + (loss_w - 1)*(st_w - 1);
n1 = in_n * in_c * in_h * in_w; //loss tensor size
n2 = filt_n * filt_c * filt_h * filt_w; //filter tensor size
pad1 = (filt_h - 1) + pad; //padding size with dilate
oh = (in_h+2*pad1-filt_h) + 1; //output deconvolute tensor size. caution stride=1.
ow = (in_w+2*pad1-filt_w) + 1; //
n3 = in_n * filt_c * oh * ow; //
a = (float *) a_bin.data;
b = (float *) b_bin.data;
a1 = (float *) enif_alloc(n1 * sizeof(float));
b1 = (float *) enif_alloc(n2 * sizeof(float));
c = (float *) enif_make_new_binary(env, n3 * sizeof(float), &c_bin);
//rotate 180 degree
for(i=0;i<filt_n;i++){
for(j=0;j<filt_c;j++){
for(k=0;k<filt_h;k++){
for(l=0;l<filt_w;l++){
b1[IDX4C(i,j,filt_h-k-1,filt_w-l-1,filt_c,filt_h,filt_w)] = b[IDX4C(i,j,k,l,filt_c,filt_h,filt_w)];
}
}
}
}
// dilate
for(i=0;i<n1;i++){
a1[i] = 0.0;
}
CHECK(cudaMalloc((void**)&dev_a1, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_a, in_n*1*loss_h*loss_w * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n2 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n3 * sizeof(float)));
CHECK(cudaMemcpy(dev_a1, a1, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_a, a, in_n*1*loss_h*loss_w * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b1, n2 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n3 * sizeof(float), cudaMemcpyHostToDevice));
dim3 blocks(in_n,1,1);
dim3 threads(filt_c,1,1);
deconvolute2_kernel <<<blocks, filt_c>> >(dev_a1, dev_a, dev_b, dev_c, filt_n, filt_c, filt_h, filt_w, st_h, st_w, pad1, in_c, in_h, in_w, loss_h, loss_w);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n3 * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_a1);
cudaFree(dev_b);
cudaFree(dev_c);
enif_free(a1);
enif_free(b1);
return(c_bin);
}
__global__ void gradfilter1_kernel(float *a, float *b, float *c, int filt_n, int filt_c, int filt_h, int filt_w, int loss_c, int loss_h, int loss_w, int st_h, int st_w, int pad, int in_c, int in_h, int in_w, int n)
{
int bid = blockIdx.x;
int tid = threadIdx.x;
int n1,c1,c2,h1,w1,h2,w2,h3,w3;
float sum,elt1,elt2;
n1 = bid;
c2 = tid;
for(c1=0;c1<filt_c;c1++){
//h1,w1 is index of filter
for(h1=0;h1<filt_h;h1++){
for(w1=0;w1<filt_w;w1++){
//h2,w2 is index of loss tensor
sum = 0.0;
for(h2=0;h2<loss_h;h2++){
for(w2=0;w2<loss_w;w2++){
//h3,w3 is index of input tensor
h3 = h1 - pad + h2;
w3 = w1 - pad + w2;
if(h3>=0 && h3<in_h && w3>=0 && w3<in_w){
elt1 = a[IDX4C(n1,c1,h3,w3,in_c,in_h,in_w)]; //input tensor
elt2 = b[IDX4C(n1,c2,h2,w2,loss_c,loss_h,loss_w)]; //loss tensor
sum = sum + elt1*elt2;
}
}
}
//set filter tensor
c[IDX5C(n1,c2,c1,h1,w1,filt_n,filt_c,filt_h,filt_w)] = sum;
}
}
}
}
/*
1st arg in_n of input tensor
2nd arg in_c of input tensor
3rd arg in_h of input tensor
4th arg in_w of input tensor
5th arg filt_n of filter tensor
6th arg filt_c of filter tensor
7th arg filt_h of filter tensor
8th arg filt_w of filter tensor
9th arg loss_c of loss tensor
10th arg loss_h of loss tensor
11th arg loss_w of loss tensor
12th arg binary of filter tensor
13th arg binary of loss tensor
14th arg stride hight
15th arg stride width
16th arg padding
*/
static ERL_NIF_TERM
gradfilter1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin,d_bin;
int in_n,in_c,in_h,in_w,filt_n,filt_c,filt_h,filt_w,loss_c,loss_h,loss_w,st_h,st_w,pad,n1,n2,n3,n4,i,j,k,l,m;
float *a,*b,*c,*d;
float *dev_a, *dev_b, *dev_c;
float elt;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &filt_n)) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &filt_c)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &filt_h)) return enif_make_int(env,7);
if (!enif_get_int(env, argv[7], &filt_w)) return enif_make_int(env,8);
if (!enif_get_int(env, argv[8], &loss_c)) return enif_make_int(env,9);
if (!enif_get_int(env, argv[9], &loss_h)) return enif_make_int(env,10);
if (!enif_get_int(env, argv[10], &loss_w)) return enif_make_int(env,11);
if (!enif_inspect_binary(env, argv[11], &a_bin )) return enif_make_int(env,12);
if (!enif_inspect_binary(env, argv[12], &b_bin )) return enif_make_int(env,13);
if (!enif_get_int(env, argv[13], &st_h)) return enif_make_int(env,14);
if (!enif_get_int(env, argv[14], &st_w)) return enif_make_int(env,15);
if (!enif_get_int(env, argv[15], &pad)) return enif_make_int(env,16);
n1 = in_n * in_c * in_h * in_w;
n2 = in_n * loss_c * loss_h * loss_w;
n3 = in_n * filt_n * filt_c * filt_h * filt_w;
n4 = filt_n * filt_c * filt_h * filt_w;
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n3 * sizeof(float), &c_bin);
d = (float *) enif_make_new_binary(env, n4 * sizeof(float), &d_bin);
//initialize c
for(i=0;i<n3;i++){
c[i] = 0.0;
}
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n2 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n3 * sizeof(float)));
// copy from host a,b,c to GPU dev_a, dev_b, dev_c
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n2 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n3 * sizeof(float), cudaMemcpyHostToDevice));
dim3 blocks(in_n,1,1);
dim3 threads(filt_n,1,1);
gradfilter1_kernel <<<blocks, threads>>>(dev_a, dev_b, dev_c, filt_n, filt_c, filt_h, filt_w, loss_c, loss_h, loss_w, st_h, st_w, pad, in_c, in_h, in_w, in_n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n3 * sizeof(float), cudaMemcpyDeviceToHost));
//average
// clear d
for(i=0;i<n4;i++){
d[i] = 0.0;
}
// copy from c to d and compute sum
for(i=0;i<in_n;i++){
for(j=0;j<filt_n;j++){
for(k=0;k<filt_c;k++){
for(l=0;l<filt_h;l++){
for(m=0;m<filt_w;m++){
elt = c[IDX5C(i,j,k,l,m,filt_n,filt_c,filt_h,filt_w)];
d[IDX4C(j,k,l,m,filt_c,filt_h,filt_w)] = d[IDX4C(j,k,l,m,filt_c,filt_h,filt_w)] + elt;
}
}
}
}
}
// average
for(i=0;i<n4;i++){
d[i] = d[i] / (float)in_n;
}
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(d_bin);
}
__global__ void gradfilter2_kernel(float *a, float *b1, float *b, float *c, int filt_n, int filt_c, int filt_h, int filt_w, int loss_c, int loss_h, int loss_w, int st_h, int st_w, int pad, int in_c, int in_h, int in_w, int n)
{
int bid = blockIdx.x;
int tid = threadIdx.x;
int n1,c1,c2,h1,w1,h2,w2,h3,w3,loss_h1,loss_w1,j,k,l,k1,l1;
float sum,elt1,elt2;
n1 = bid;
c2 = tid;
//dilated loss tensor size
loss_h1 = loss_h+(loss_h-1)*(st_h-1);
loss_w1 = loss_w+(loss_w-1)*(st_w-1);
//dilate loss tensor.
for(j=0;j<loss_c;j++){
for(k=0;k<loss_h;k++){
for(l=0;l<loss_w;l++){
elt1 = b[IDX4C(n1,j,k,l,loss_c,loss_h,loss_w)];
k1 = st_h*k;
l1 = st_w*l;
b1[IDX4C(n1,j,k1,l1,loss_c,loss_h1,loss_w1)] = elt1;
}
}
}
//convolute input tensor with dilated loss tensor. cuation stride is always 1.
for(c1=0;c1<filt_c;c1++){
//h1,w1 is index of filter
for(h1=0;h1<filt_h;h1++){
for(w1=0;w1<filt_w;w1++){
//h2,w2 is index of loss tensor
sum = 0.0;
for(h2=0;h2<loss_h1;h2++){
for(w2=0;w2<loss_w1;w2++){
//h3,w3 is index of input tensor
h3 = h1 - pad + h2;
w3 = w1 - pad + w2;
if(h3>=0 && h3<in_h && w3>=0 && w3<in_w){
elt1 = a[IDX4C(n1,c1,h3,w3,in_c,in_h,in_w)]; //input tensor
elt2 = b1[IDX4C(n1,c2,h2,w2,loss_c,loss_h1,loss_w1)]; //loss tensor
sum = sum + elt1*elt2;
}
}
}
//set filter tensor
c[IDX5C(n1,c2,c1,h1,w1,filt_n,filt_c,filt_h,filt_w)] = + sum;
}
}
}
}
/*
dilate loss tensor
e.g.
|1.0,2.0|
|3.0,4.0|
dilated stride=2
|1.0,0.0,2.0|
|0.0,0.0,0.0|
|3.0,0.0,4.0|
*/
/*
gradfilter2 is for stride >= 2. This one requires dilate
1st arg in_n of input tensor
2nd arg in_c of input tensor
3rd arg in_h of input tensor
4th arg in_w of input tensor
5th arg filt_n of filter tensor
6th arg filt_c of filter tensor
7th arg filt_h of filter tensor
8th arg filt_w of filter tensor
9th arg loss_c of loss tensor
10th arg loss_h of loss tensor
11th arg loss_w of loss tensor
12th arg binary of filter tensor
13th arg binary of loss tensor
14th arg stride hight
15th arg stride width
16th arg padding
*/
static ERL_NIF_TERM
gradfilter2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin,d_bin;
int in_n,in_c,in_h,in_w,filt_n,filt_c,filt_h,filt_w,loss_c,loss_h,loss_w,st_h,st_w,pad,n1,n2,n3,n4,n5,i,j,k,l,m;
float *a,*b,*b1,*c,*d;
float *dev_a, *dev_b, *dev_b1, *dev_c;
float elt;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &filt_n)) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &filt_c)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &filt_h)) return enif_make_int(env,7);
if (!enif_get_int(env, argv[7], &filt_w)) return enif_make_int(env,8);
if (!enif_get_int(env, argv[8], &loss_c)) return enif_make_int(env,9);
if (!enif_get_int(env, argv[9], &loss_h)) return enif_make_int(env,10);
if (!enif_get_int(env, argv[10], &loss_w)) return enif_make_int(env,11);
if (!enif_inspect_binary(env, argv[11], &a_bin )) return enif_make_int(env,12);
if (!enif_inspect_binary(env, argv[12], &b_bin )) return enif_make_int(env,13);
if (!enif_get_int(env, argv[13], &st_h)) return enif_make_int(env,14);
if (!enif_get_int(env, argv[14], &st_w)) return enif_make_int(env,15);
if (!enif_get_int(env, argv[15], &pad)) return enif_make_int(env,16);
n1 = in_n * in_c * in_h * in_w;
n2 = in_n * loss_c * loss_h * loss_w;
n3 = in_n * filt_n * filt_c * filt_h * filt_w;
n4 = filt_n * filt_c * filt_h * filt_w;
n5 = in_n * loss_c * (loss_h+(loss_h-1)*(st_h-1)) * (loss_w+(loss_w-1)*(st_w-1)); // dilated loss tensor size
a = (float *) a_bin.data;
b = (float *) b_bin.data;
b1 = (float *) enif_alloc(n5 * sizeof(float)); // dilate loss tensor area
c = (float *) enif_make_new_binary(env, n3 * sizeof(float), &c_bin);
d = (float *) enif_make_new_binary(env, n4 * sizeof(float), &d_bin);
//initialize c
for(i=0;i<n3;i++){
c[i] = 0.0;
}
//initialize b1
for(i=0;i<n5;i++){
b1[i] = 0.0;
}
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n2 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b1, n5 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n3 * sizeof(float)));
// copy from host a,b,c to GPU dev_a, dev_b, dev_c
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n2 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b1, b1, n5 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n3 * sizeof(float), cudaMemcpyHostToDevice));
dim3 blocks(in_n,1,1);
dim3 threads(filt_n,1,1);
gradfilter2_kernel <<<blocks, threads>> >(dev_a, dev_b1, dev_b, dev_c, filt_n, filt_c, filt_h, filt_w, loss_c, loss_h, loss_w, st_h, st_w, pad, in_c, in_h, in_w, in_n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n3 * sizeof(float), cudaMemcpyDeviceToHost));
//average
// clear d
for(i=0;i<n4;i++){
d[i] = 0.0;
}
// copy from c to d and compute sum
for(i=0;i<in_n;i++){
for(j=0;j<filt_n;j++){
for(k=0;k<filt_c;k++){
for(l=0;l<filt_h;l++){
for(m=0;m<filt_w;m++){
elt = c[IDX5C(i,j,k,l,m,filt_n,filt_c,filt_h,filt_w)];
d[IDX4C(j,k,l,m,filt_c,filt_h,filt_w)] = d[IDX4C(j,k,l,m,filt_c,filt_h,filt_w)] + elt;
}
}
}
}
}
// average
for(i=0;i<n4;i++){
d[i] = d[i] / (float)in_n;
}
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_b1);
cudaFree(dev_c);
enif_free(b1);
return(d_bin);
}
__global__ void full_kernel(float *a, float *b, int in_n, int in_c, int in_h, int in_w, int n)
{
int tid = threadIdx.x;
int n1,i,j,k;
float elt;
if(tid < n)
{
n1 = tid;
for(i=0;i<in_c;i++){
for(j=0;j<in_h;j++){
for(k=0;k<in_w;k++){
elt = a[IDX4C(n1,i,j,k,in_c,in_h,in_w)];
b[IDX2C(n1,i*in_h*in_w + j*in_w + k,in_n)] = elt;
}
}
}
}
}
/*
1st arg in_n of input tensor 4DIM
2nd arg in_c of input tensor
3rd arg in_h of input tensor
4th arg in_w of input tensor
5th arg binary of input tensor
*/
static ERL_NIF_TERM
full1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int in_n,in_c,in_h,in_w,n1,n;
float *a,*b;
float *dev_a, *dev_b;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
n1 = in_n * in_c * in_h * in_w;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n1 * sizeof(float), &b_bin);
n = in_n;
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n1 * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n1 * sizeof(float), cudaMemcpyHostToDevice));
full_kernel << <1, n>> >(dev_a, dev_b, in_n, in_c, in_h, in_w, n);
// copy to host d from GPU dev_d
CHECK(cudaMemcpy(b, dev_b, n1 * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
return(b_bin);
}
__global__ void unfull_kernel(float *a, float *b, int in_n, int in_c, int in_h, int in_w, int n)
{
int tid = threadIdx.x;
int n1,i,j,k;
float elt;
if(tid < n)
{
n1 = tid;
for(i=0;i<in_c;i++){
for(j=0;j<in_h;j++){
for(k=0;k<in_w;k++){
elt = a[IDX2C(n1,i*in_h*in_w + j*in_w + k,in_n)];
b[IDX4C(n1,i,j,k,in_c,in_h,in_w)] = elt;
}
}
}
}
}
/*
1st arg in_n of input tensor 4DIM
2nd arg in_c of input tensor
3rd arg in_h of input tensor
4th arg in_w of input tensor
5th arg binary of input tensor
*/
static ERL_NIF_TERM
unfull1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int in_n,in_c,in_h,in_w,n1,n;
float *a,*b;
float *dev_a, *dev_b;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
n1 = in_n * in_c * in_h * in_w;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n1 * sizeof(float), &b_bin);
n = in_n;
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n1 * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n1 * sizeof(float)));
// copy from host a,b1,c to GPU dev_a, dev_b, dev_c
CHECK(cudaMemcpy(dev_a, a, n1 * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n1 * sizeof(float), cudaMemcpyHostToDevice));
unfull_kernel << <1, n>> >(dev_a, dev_b, in_n, in_c, in_h, in_w, n);
// copy to host d from GPU dev_d
CHECK(cudaMemcpy(b, dev_b, n1 * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
return(b_bin);
}
static ERL_NIF_TERM
new1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int n,i;
ERL_NIF_TERM a_bin;
float *a;
double d;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_get_double(env, argv[1], &d)) return enif_make_int(env,2);
a = (float *) enif_make_new_binary(env, n * sizeof(float), &a_bin);
// Set matrix data
for(i=0;i<n;i++){
a[i] = (float)d;
}
return(a_bin);
}
static ERL_NIF_TERM
new2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int r1,c1,i,j;
ERL_NIF_TERM head, list, a_bin;
float *a;
double d;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
a = (float *) enif_make_new_binary(env, r1 * c1 * sizeof(float), &a_bin);
// Set matrix data
list = argv[2]; /* matrix1 */
for(i=0;i<r1;i++){
for(j=0;j<c1;j++){
enif_get_list_cell(env, list, &head, &list);
enif_get_double(env,head,&d);
a[IDX2C(i,j,r1)] = (float)d;
}
}
return(a_bin);
}
static ERL_NIF_TERM
new3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int c,h,w,i,j,k;
ERL_NIF_TERM head, list, a_bin;
float *a;
double d;
if (!enif_get_int(env, argv[0], &c)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &h)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &w)) return enif_make_int(env,3);
a = (float *) enif_make_new_binary(env, c * h * w * sizeof(float), &a_bin);
// Set matrix data
list = argv[3]; /* matrix1 */
for(i=0;i<c;i++){
for(j=0;j<h;j++){
for(k=0;k<w;k++){
enif_get_list_cell(env, list, &head, &list);
enif_get_double(env,head,&d);
a[IDX3C(i,j,k,h,w)] = (float)d;
}
}
}
return(a_bin);
}
static ERL_NIF_TERM
new4(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int n,c,h,w,i,j,k,l;
ERL_NIF_TERM head, list, a_bin;
float *a;
double d;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &w)) return enif_make_int(env,4);
a = (float *) enif_make_new_binary(env, n * c * h * w * sizeof(float), &a_bin);
// Set matrix data
list = argv[4]; /* matrix1 */
for(i=0;i<n;i++){
for(j=0;j<c;j++){
for(k=0;k<h;k++){
for(l=0;l<w;l++){
enif_get_list_cell(env, list, &head, &list);
enif_get_double(env,head,&d);
a[IDX4C(i,j,k,l,c,h,w)] = (float)d;
}
}
}
}
return(a_bin);
}
static ERL_NIF_TERM
rand1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int n,i;
float x,y,val;
float *result_data;
ERL_NIF_TERM result;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
result_data = (float *) enif_make_new_binary(env, n * sizeof(float), &result);
srand((unsigned) time(NULL));
for(i=0;i<n;i++){
//box_muller
x = (float)rand()/(float)RAND_MAX;
y = (float)rand()/(float)RAND_MAX;
val = sqrt(-2.0 * log(x)) * cos(2.0 * PI * y);
result_data[i] = val;
}
return(result);
}
static ERL_NIF_TERM
mult1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int r1, c1, r2, c2, n, i, j;
float *a,*b,*c;
float* devPtrA;
float* devPtrB;
float* devPtrC;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &r2)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &c2)) return enif_make_int(env,5);
if (!enif_inspect_binary(env, argv[5], &b_bin)) return enif_make_int(env,6);
n = r1*c2;
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
for(j=0;j<c2;j++)
for(i=0;i<r1;i++)
c[IDX2C(i,j,r1)] = 0.0;
// Initialize CUBLAS
cublasInit();
CUBLAS(cublasAlloc (r1*c1, sizeof(*a), (void**)&devPtrA));
CUBLAS(cublasAlloc (r2*c2, sizeof(*b), (void**)&devPtrB));
CUBLAS(cublasAlloc (r1*c2, sizeof(*c), (void**)&devPtrC));
CUBLAS(cublasSetMatrix (r1, c1, sizeof(*a), a, r1, devPtrA, r1));
CUBLAS(cublasSetMatrix (r2, c2, sizeof(*b), b, r2, devPtrB, r2));
CUBLAS(cublasSetMatrix (r1, c2, sizeof(*c), c, r1, devPtrC, r1));
//Sgemm
cublasSgemm('N', 'N', r1, c2, c1, 1.0, devPtrA, r1, devPtrB, r2, 0.0, devPtrC, r1);
CUBLAS(cublasGetMatrix (r1, c2, sizeof(*c), devPtrC, r1, c, r1));
// Shutdown CUBLAS
cublasFree(devPtrA);
cublasFree(devPtrB);
cublasFree(devPtrC);
cublasShutdown();
return(c_bin);
}
__global__ void add1_kernel(float *a, float *b, float *c, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
c[tid] = a[tid] + b[tid];
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
add1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int n;
float *a,*b,*c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
add1_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
__global__ void sub1_kernel(float *a, float *b, float *c, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
c[tid] = a[tid] - b[tid];
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
sub1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int n;
float *a,*b,*c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
sub1_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
__global__ void emult1_kernel(float *a, float *b, float *c, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
c[tid] = a[tid] * b[tid];
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
emult1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int n;
float *a,*b,*c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
emult1_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
static ERL_NIF_TERM
transpose1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int r1, c1, n, i, j;
float *a,*b;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
n = r1*c1;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
for(i=0;i<r1;i++){
for(j=0;j<c1;j++){
b[IDX2C(j,i,c1)] = a[IDX2C(i,j,r1)];
}
}
return(b_bin);
}
static ERL_NIF_TERM
ident1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int n,i,j;
ERL_NIF_TERM a_bin;
float *a;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
a = (float *) enif_make_new_binary(env, n * n * sizeof(float), &a_bin);
// Set matrix data
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(i==j)
a[IDX2C(i,j,n)] = 1.0;
else
a[IDX2C(i,j,n)] = 0.0;
}
}
return(a_bin);
}
__global__ void sigmoid_kernel(float *a, float *b, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
b[tid] = SIGMOID(a[tid]);
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
activate_sigmoid(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int n;
float *a,*b;
float *dev_a, *dev_b;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
sigmoid_kernel << <128, 128 >> >(dev_a, dev_b, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(b, dev_b, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
return(b_bin);
}
__global__ void tanh_kernel(float *a, float *b, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
b[tid] = tanh(a[tid]);
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
activate_tanh(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int n;
float *a,*b;
float *dev_a, *dev_b;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
tanh_kernel << <128, 128 >> >(dev_a, dev_b, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(b, dev_b, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
return(b_bin);
}
__global__ void relu_kernel(float *a, float *b, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
if(a[tid] >= 0)
b[tid] = a[tid];
else
b[tid] = 0.0;
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
activate_relu(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int n;
float *a,*b;
float *dev_a, *dev_b;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
relu_kernel << <128, 128 >> >(dev_a, dev_b, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(b, dev_b, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
return(b_bin);
}
static ERL_NIF_TERM
activate_softmax(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int r1, c1, n, i, j, k;
float *a,*b;
float max,sum,delta;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
n = r1*c1;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
//calculate softmax
delta = 0.01;
for(i=0;i<r1;i++){
for(j=0;j<c1;j++){
max = -3.402823e38;
for(k=0;k<c1;k++){
if(a[IDX2C(i,k,r1)] > max)
max = a[IDX2C(i,k,r1)];
}
sum = 0.0;
for(k=0;k<c1;k++){
sum = sum + exp(a[IDX2C(i,k,r1)] - max);
}
b[IDX2C(i,j,r1)] = exp(a[IDX2C(i,j,r1)] - max) / (sum+delta);
}
}
return(b_bin);
}
__global__ void differ_sigmoid_kernel(float *a, float *b, float *c, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
c[tid] = a[tid] * ((1 - SIGMOID(b[tid])) * SIGMOID(b[tid]));
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
differ_sigmoid(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int n;
float *a,*b,*c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
differ_sigmoid_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
__global__ void differ_tanh_kernel(float *a, float *b, float *c, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
c[tid] = a[tid] * (1/(cosh(b[tid]) * cosh(b[tid])));
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
differ_tanh(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int n;
float *a,*b,*c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
differ_tanh_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
__global__ void differ_relu_kernel(float *a, float *b, float *c, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
if(b[tid] >= 0)
c[tid] = a[tid];
else
c[tid] = 0.0;
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
differ_relu(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int n;
float *a,*b,*c;
float *dev_a, *dev_b, *dev_c;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,4);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
differ_relu_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
__global__ void smult_kernel(float d, float *a, float *b, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
b[tid] = d * a[tid];
tid += blockDim.x * gridDim.x;
}
}
static ERL_NIF_TERM
smult1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int n;
float *a,*b;
float *dev_a, *dev_b;
double s;
if (!enif_get_double(env, argv[0], &s)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &n)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
smult_kernel << <128, 128 >> >((float)s,dev_a, dev_b, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(b, dev_b, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
return(b_bin);
}
static ERL_NIF_TERM
trace1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM result;
int r1, c1, i, j;
float *a;
float trace;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
trace = 0.0;
for(i=0;i<r1;i++){
for(j=0;j<c1;j++){
if(i==j)
trace = trace + a[IDX2C(i,j,r1)];
}
}
result = enif_make_double(env,trace);
return(result);
}
static ERL_NIF_TERM
mean_square(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM result;
int r1, c1, i, j;
float *a, *b;
float d,s;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[3], &b_bin )) return enif_make_int(env,4);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
s = 0.0;
for(i=0;i<r1;i++){
for (j=0;j<c1;j++){
d = a[IDX2C(i,j,r1)] - b[IDX2C(i,j,r1)];
s = s + d*d;
}
}
s = s / (2.0*(float(r1)));
result = enif_make_double(env,s);
return(result);
}
static ERL_NIF_TERM
cross_entropy(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM result;
int r1, c1, i, j;
float *a, *b;
float d,s,delta;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[3], &b_bin )) return enif_make_int(env,4);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
delta = 1e-7;
s = 0.0;
for(i=0;i<r1;i++){
for (j=0;j<c1;j++){
d = a[IDX2C(i,j,r1)] + delta;
s = s + b[IDX2C(i,j,r1)] * log(d);
}
}
s = -1.0 * s / (float)r1;
result = enif_make_double(env,s);
return(result);
}
static ERL_NIF_TERM
elt1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM result;
int r1, c1, i, j;
float *a;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &i)) enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &j)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
a = (float *) a_bin.data;
result = enif_make_double(env,(double)a[IDX2C(i,j,r1)]);
return(result);
}
static ERL_NIF_TERM
set1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int r1, c1, n, i, j, x, y;
float *a,*b;
double val;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &x)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &y)) return enif_make_int(env,5);
if (!enif_get_double(env, argv[5], &val)) return enif_make_int(env,6);
n = r1*c1;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
for(i=0;i<r1;i++){
for(j=0;j<c1;j++){
if(i==x && j==y)
b[IDX2C(i,j,r1)] = (float)val;
else
b[IDX2C(i,j,r1)] = a[IDX2C(i,j,r1)];
}
}
return(b_bin);
}
static ERL_NIF_TERM
add_diff1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int r1, c1, n, i, j, x, y;
float *a,*b;
double val;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &x)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &y)) return enif_make_int(env,5);
if (!enif_get_double(env, argv[5], &val)) return enif_make_int(env,6);
n = r1*c1;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
for(i=0;i<r1;i++){
for(j=0;j<c1;j++){
if(i==x && j==y)
b[IDX2C(i,j,r1)] = a[IDX2C(i,j,r1)] + (float)val;
else
b[IDX2C(i,j,r1)] = a[IDX2C(i,j,r1)];
}
}
return(b_bin);
}
static ERL_NIF_TERM
add_diff2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int n1, c1, h1, w1, n, i, j, k, l, n2, c2, h2, w2;
float *a,*b;
double val;
if (!enif_get_int(env, argv[0], &n1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &h1)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &w1)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &n2)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &c2)) return enif_make_int(env,7);
if (!enif_get_int(env, argv[7], &h2)) return enif_make_int(env,8);
if (!enif_get_int(env, argv[8], &w2)) return enif_make_int(env,9);
if (!enif_get_double(env, argv[9], &val)) return enif_make_int(env,10);
n = n1*c1*h1*w1;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n * sizeof(float), &b_bin);
for(i=0;i<n1;i++){
for(j=0;j<c1;j++){
for(k=0;k<h1;k++){
for(l=0;l<w1;l++){
if(i==n2 && j==c2 && k==h2 && l==w2){
b[IDX4C(i,j,k,l,c1,h1,w1)] = a[IDX4C(i,j,k,l,c1,h1,w1)] + (float)val;
}
else {
b[IDX4C(i,j,k,l,c1,h1,w1)] = a[IDX4C(i,j,k,l,c1,h1,w1)];
}
}
}
}
}
return(b_bin);
}
static ERL_NIF_TERM
average1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int r1, c1, i, j;
float *a,*b;
float sum;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, c1 * sizeof(float), &b_bin);
for(j=0;j<c1;j++){
sum = 0.0;
for(i=0;i<r1;i++){
sum = sum + a[IDX2C(i,j,r1)];
}
b[j] = sum / (float)r1;
}
return(b_bin);
}
/*
1st arg row-size of matrix
2nd arg col-size of matrix
3rd arg matrix data binary
*/
static ERL_NIF_TERM
sum1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM result;
int r1, c1, i, j;
float *a;
float sum;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
sum = 0.0;
for(i=0;i<r1;i++){
for(j=0;j<c1;j++){
sum = sum + a[IDX2C(i,j,r1)];
}
}
result = enif_make_double(env,sum);
return(result);
}
/*
transfer 2 DIm matrix to list
*/
static ERL_NIF_TERM
to_list1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM head,list;
int r1, c1, i, j;
float *a;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
list = enif_make_list(env, 0);
for(i=r1-1;i>=0;i--){
for(j=c1-1;j>=0;j--){
head = enif_make_double(env,(double)a[IDX2C(i,j,r1)]);
list = enif_make_list_cell(env,head,list);
}
}
return(list);
}
/*
transfer 3 DIm matrix to list
*/
static ERL_NIF_TERM
to_list2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM head,list;
int c, h, w, i, j, k;
float *a;
if (!enif_get_int(env, argv[0], &c)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &h)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &w)) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[3], &a_bin )) return enif_make_int(env,4);
a = (float *) a_bin.data;
list = enif_make_list(env, 0);
for(i=c-1;i>=0;i--){
for(j=h-1;j>=0;j--){
for(k=w-1;k>=0;k--){
head = enif_make_double(env,(double)a[IDX3C(i,j,k,h,w)]);
list = enif_make_list_cell(env,head,list);
}
}
}
return(list);
}
/*
transfer 4 DIm matrix to list
*/
static ERL_NIF_TERM
to_list3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM head,list;
int n, c, h, w, i, j, k, l;
float *a;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &w)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_badarg(env);
a = (float *) a_bin.data;
list = enif_make_list(env, 0);
for(i=n-1;i>=0;i--){
for(j=c-1;j>=0;j--){
for(k=h-1;k>=0;k--){
for(l=w-1;l>=0;l--){
head = enif_make_double(env,(double)a[IDX4C(i,j,k,l,c,h,w)]);
list = enif_make_list_cell(env,head,list);
}
}
}
}
return(list);
}
__global__ void dropout1_kernel(float *a, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
a[tid] = 1.0;
tid += blockDim.x * gridDim.x;
}
}
/*
1st arg size of mask tensor
2nd arg rate of dropout
return mask tensor
element of mask tensor is basicaly 1.0.
element of dropout rate is 0.0.
when forward and backward, generate Hadamard product with mask tensor
*/
static ERL_NIF_TERM
dropout1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM a_bin;
int n,count,i,j;
float *a,*dev_a;
double dropout_rate;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_get_double(env, argv[1], &dropout_rate)) return enif_make_int(env,2);
a = (float *) enif_make_new_binary(env, n * sizeof(float), &a_bin);
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
dropout1_kernel << <128, 128 >> >(dev_a, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(a, dev_a, n * sizeof(float), cudaMemcpyDeviceToHost));
// dropout
count = (int)(double(n)*dropout_rate);
for(i=0;i<count;i++){
j = rand() % n;
a[j] = 0.0;
}
// free
cudaFree(dev_a);
return(a_bin);
}
__global__ void sgd1_kernel(float *a, float *b, float *c, float lr, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
c[tid] = a[tid] - b[tid]*lr;
tid += blockDim.x * gridDim.x;
}
}
/*
w - g*lr
w is weight matrix.
g is gradient matrix.
when element of w is zero result is zero. This means dropout.
return updated weight matrix.
1st arg is size of vectorized matrix
2nd arg is weight matrix or tensor
3rd arg is gradient matrix or tensor
4th arg is learning rate
*/
static ERL_NIF_TERM
sgd1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin, b_bin;
ERL_NIF_TERM c_bin;
int n;
float *a,*b,*c,*dev_a, *dev_b, *dev_c;
float lr;
double learning_rate;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
if (!enif_get_double(env, argv[3], &learning_rate)) return enif_make_int(env,4);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n * sizeof(float), &c_bin);
lr = (float) learning_rate;
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
sgd1_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, lr, n);
// copy to host c from GPU dev_c
CHECK(cudaMemcpy(c, dev_c, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return(c_bin);
}
/*
def momentum(v, g, lr) do
Matrex.apply(v, g, fn v, g -> 0.5 * v - lr * g end)
end
*/
__global__ void momentum_kernel(float *a, float *b, float *c, float *d, float *e, float lr, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < n)
{
d[tid] = ((0.9 * b[tid]) - (lr * c[tid]));
e[tid] = a[tid] + d[tid];
tid += blockDim.x * gridDim.x;
}
}
/*
1st arg row-size of vectorized each-matrix
2nd arg wight-matrix (a)
3rd arg v-matrix (b)
4th arg gradient-matrix (c)
5th arg learning rate
return tuple {next_v-mattrix,weight_matrix}
*/
static ERL_NIF_TERM
momentum1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin,c_bin;
ERL_NIF_TERM d_bin,e_bin,tuple;
int n;
float *a,*b,*c,*d,*e;
float *dev_a, *dev_b, *dev_c ,*dev_d, *dev_e;
float lr;
double learning_rate;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin )) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[3], &c_bin )) return enif_make_int(env,4);
if (!enif_get_double(env, argv[4], &learning_rate)) return enif_make_int(env,5);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) c_bin.data;
d = (float *) enif_make_new_binary(env, n * sizeof(float), &d_bin);
e = (float *) enif_make_new_binary(env, n * sizeof(float), &e_bin);
lr = (float) learning_rate;
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_d, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_e, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_d, d, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_e, e, n * sizeof(float), cudaMemcpyHostToDevice));
momentum_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, dev_d, dev_e, lr, n);
// copy to host d from GPU dev_d
CHECK(cudaMemcpy(d, dev_d, n * sizeof(float), cudaMemcpyDeviceToHost));
CHECK(cudaMemcpy(e, dev_e, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
cudaFree(dev_d);
cudaFree(dev_e);
tuple = enif_make_tuple2(env,d_bin,e_bin);
return(tuple);
}
/* ADAGRAD
h1 = h + grad*grad
lr1 = lr/(sqrt(h1))
w1 = w - lr1 * grad
a[] = w
b[] = h
c[] = grad
d[] = h1
e[] = w1
*/
__global__ void adagrad_kernel(float *a, float *b, float *c, float *d, float *e, float lr, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
float lr1;
while (tid < n)
{
d[tid] = b[tid] + c[tid]*c[tid];
lr1 = lr/(sqrt(d[tid]));
e[tid] = a[tid] - lr1 * c[tid];
tid += blockDim.x * gridDim.x;
}
}
/*
1st arg row-size of vectorized each-matrix
2nd arg wight-matrix (a_bin)
3rd arg h-matrix (b_bin)
4th arg grad-matrix (c_bin)
5th arg learning rate
return tuple {new-h,new-w}
*/
static ERL_NIF_TERM
adagrad1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin,c_bin;
ERL_NIF_TERM d_bin,e_bin,tuple;
int n;
float *a,*b,*c,*d,*e;
float *dev_a, *dev_b, *dev_c, *dev_d, *dev_e;
float lr;
double learning_rate;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[3], &c_bin)) return enif_make_int(env,4);
if (!enif_get_double(env, argv[4], &learning_rate)) return enif_make_int(env,5);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) c_bin.data;
d = (float *) enif_make_new_binary(env, n * sizeof(float), &d_bin);
e = (float *) enif_make_new_binary(env, n * sizeof(float), &e_bin);
lr = (float) learning_rate;
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_d, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_e, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_d, d, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_e, e, n * sizeof(float), cudaMemcpyHostToDevice));
adagrad_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, dev_d, dev_e, lr, n);
// copy to host d,e from GPU dev_d,dev_e
CHECK(cudaMemcpy(d, dev_d, n * sizeof(float), cudaMemcpyDeviceToHost));
CHECK(cudaMemcpy(e, dev_e, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
cudaFree(dev_d);
cudaFree(dev_e);
tuple = enif_make_tuple2(env,d_bin,e_bin);
return(tuple);
}
/* RMSprop
h1 = alpha * h + (1 - alpha) * grad*grad
lr1 = lr /(sqrt(h) + epsilon)
w1 = w - lr1 * grad
a[] = w
b[] = h
c[] = grad
d[] = h1
e[] = w1
*/
__global__ void rms_kernel(float *a, float *b, float *c, float *d, float *e, float lr, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
float lr1,alpha,epsilon;
alpha = 0.99;
epsilon = 10.0e-7;
while (tid < n)
{
d[tid] = alpha * b[tid] + (1-alpha)*c[tid]*c[tid];
lr1 = lr/(sqrt(d[tid])+epsilon);
e[tid] = a[tid] - lr1*c[tid];
tid += blockDim.x * gridDim.x;
}
}
/*
1st arg row-size of vectorized each-matrix
2nd arg wight-matrix (a_bin)
3rd arg h-matrix (b_bin)
4th arg grad-matrix (c_bin)
5th arg learning rate
return tuple {new-h,new-w}
*/
static ERL_NIF_TERM
rms1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin,c_bin;
ERL_NIF_TERM d_bin,e_bin,tuple;
int n;
float *a,*b,*c,*d,*e;
float *dev_a, *dev_b, *dev_c, *dev_d, *dev_e;
float lr;
double learning_rate;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[3], &c_bin)) return enif_make_int(env,4);
if (!enif_get_double(env, argv[4], &learning_rate)) return enif_make_int(env,5);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) c_bin.data;
d = (float *) enif_make_new_binary(env, n * sizeof(float), &d_bin);
e = (float *) enif_make_new_binary(env, n * sizeof(float), &e_bin);
lr = (float) learning_rate;
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_d, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_e, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_d, d, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_e, e, n * sizeof(float), cudaMemcpyHostToDevice));
rms_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, dev_d, dev_e, lr, n);
// copy to host d,e from GPU dev_d,dev_e
CHECK(cudaMemcpy(d, dev_d, n * sizeof(float), cudaMemcpyDeviceToHost));
CHECK(cudaMemcpy(e, dev_e, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
cudaFree(dev_d);
cudaFree(dev_e);
tuple = enif_make_tuple2(env,d_bin,e_bin);
return(tuple);
}
/* ADAM
beta1 = 0.9
beta2 = 0.999
epsilon = 10.0e-7
alpha = 0.001
m1 = beta1 * m + (1 - beta1) * grad
v1 = beta2 * v + (1 - beta2) * grad^2
m2 = m1/(1 - beta1)
v2 = v1/(1 - beta2)
w1 = w - alpha * m2/(sqrt(v2)+epsilon)
a[] is w
b[] is m
c[] is v
d[] is grad
e[] is m1
f[] is v1
g[] is w1
*/
__global__ void adam_kernel(float *a, float *b, float *c, float *d, float *e, float *f, float *g, float lr, int n)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
float beta1,beta2,epsilon,m2,v2;
beta1 = 0.9;
beta2 = 0.999;
epsilon = 10.0e-7;
//alpha = 0.001;
while (tid < n){
e[tid] = beta1 * b[tid] + (1 - beta1) * d[tid];
f[tid] = beta2 * c[tid] + (1 - beta2) * d[tid]*d[tid];
m2 = e[tid]/(1-beta1);
v2 = f[tid]/(1-beta2);
g[tid] = a[tid] - lr * (m2/(sqrt(v2)+epsilon));
tid += blockDim.x * gridDim.x;
}
}
/*
1st arg row-size of vectorized each-matrix
2nd arg w-matrix (a_bin)
3rd arg m-matrix (b_bin)
4th arg v-matrix (c_bin)
5th arg grad-matrix (d_bin)
6th arg learning rate
return tuple {m1,v1,w1}
*/
static ERL_NIF_TERM
adam1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin,c_bin,d_bin;
ERL_NIF_TERM e_bin,f_bin,g_bin,tuple;
int n;
float *a,*b,*c,*d,*e,*f,*g;
float *dev_a, *dev_b, *dev_c, *dev_d, *dev_e, *dev_f, *dev_g;
float lr;
double learning_rate;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin)) return enif_make_int(env,3);
if (!enif_inspect_binary(env, argv[3], &c_bin)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &d_bin)) return enif_make_int(env,5);
if (!enif_get_double(env, argv[5], &learning_rate)) return enif_make_int(env,6);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) c_bin.data;
d = (float *) d_bin.data;
e = (float *) enif_make_new_binary(env, n * sizeof(float), &e_bin);
f = (float *) enif_make_new_binary(env, n * sizeof(float), &f_bin);
g = (float *) enif_make_new_binary(env, n * sizeof(float), &g_bin);
lr = (float) learning_rate;
// Allocate for GPU
CHECK(cudaMalloc((void**)&dev_a, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_b, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_c, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_d, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_e, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_f, n * sizeof(float)));
CHECK(cudaMalloc((void**)&dev_g, n * sizeof(float)));
// copy from host a,b to GPU dev_a, dev_b
CHECK(cudaMemcpy(dev_a, a, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_b, b, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_c, c, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_d, d, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_e, e, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_f, f, n * sizeof(float), cudaMemcpyHostToDevice));
CHECK(cudaMemcpy(dev_g, g, n * sizeof(float), cudaMemcpyHostToDevice));
adam_kernel << <128, 128 >> >(dev_a, dev_b, dev_c, dev_d, dev_e, dev_f, dev_g, lr, n);
// copy to host d,e from GPU dev_d,dev_e
CHECK(cudaMemcpy(e, dev_e, n * sizeof(float), cudaMemcpyDeviceToHost));
CHECK(cudaMemcpy(f, dev_f, n * sizeof(float), cudaMemcpyDeviceToHost));
CHECK(cudaMemcpy(g, dev_g, n * sizeof(float), cudaMemcpyDeviceToHost));
// free
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
cudaFree(dev_d);
cudaFree(dev_e);
cudaFree(dev_f);
cudaFree(dev_g);
tuple = enif_make_tuple3(env,e_bin,f_bin,g_bin);
return(tuple);
}
/*
1st arg row-size of matrix
2nd arg col-size of matris
3rd arg predicted matrix
4th arg list of label. each element is integer
return accuracy rate
*/
static ERL_NIF_TERM
accuracy1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM head,list,result;
int r1, c1, i, j, n, index,sum;
float *a;
double max,rate;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
// calculate accuracy
sum = 0;
list = argv[3];
for(i=0;i<r1;i++){
max = 0.0;
enif_get_list_cell(env, list, &head, &list);
enif_get_int(env,head,&n);
for(j=0;j<c1;j++){
if(a[IDX2C(i,j,r1)] > max){
max = a[IDX2C(i,j,r1)];
index = j;
}
}
if(index == n)
sum++;
}
rate = (double)sum / (double)r1;
result = enif_make_double(env,rate);
return(result);
}
/*
1st arg row-size of matrix
2nd arg col-size of matris
3rd arg predicted matrix
4th arg list of label. each element is integer
return correct number
*/
static ERL_NIF_TERM
correct1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM head,list,result;
int r1, c1, i, j, n, index,sum;
float *a;
float max;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
// calculate correct number
sum = 0;
list = argv[3];
for(i=0;i<r1;i++){
max = 0.0;
enif_get_list_cell(env, list, &head, &list);
enif_get_int(env,head,&n);
for(j=0;j<c1;j++){
if(a[IDX2C(i,j,r1)] > max){
max = a[IDX2C(i,j,r1)];
index = j;
}
}
if(index == n)
sum++;
}
result = enif_make_double(env,(double)sum);
return(result);
}
static ERL_NIF_TERM
random_select1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin,d_bin,tuple;
int r1, c1, r2, c2, i, j, n, r;
float *a, *b, *c, *d;
if (!enif_get_int(env, argv[0], &r1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &a_bin )) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &r2)) return enif_make_int(env,4);
if (!enif_get_int(env, argv[4], &c2)) return enif_make_int(env,5);
if (!enif_inspect_binary(env, argv[5], &b_bin )) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &n)) return enif_make_int(env,7);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n*c1 * sizeof(float), &c_bin);
d = (float *) enif_make_new_binary(env, n*c2 * sizeof(float), &d_bin);
// random-select
for(i=0;i<n;i++){
r = rand() % r1;
for(j=0;j<c1;j++){
c[IDX2C(i,j,n)] = a[IDX2C(r,j,r1)];
}
for(j=0;j<c2;j++){
d[IDX2C(i,j,n)] = b[IDX2C(r,j,r2)];
}
}
tuple = enif_make_tuple2(env,c_bin,d_bin);
return(tuple);
}
static ERL_NIF_TERM
random_select2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
ERL_NIF_TERM c_bin,d_bin,tuple;
int n1,c1,h1,w1,r2,c2, i, j, k, l, n, r;
float *a, *b, *c, *d;
if (!enif_get_int(env, argv[0], &n1)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &c1)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &h1)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &w1)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
if (!enif_get_int(env, argv[5], &r2)) return enif_make_int(env,6);
if (!enif_get_int(env, argv[6], &c2)) return enif_make_int(env,7);
if (!enif_inspect_binary(env, argv[7], &b_bin )) return enif_make_int(env,8);
if (!enif_get_int(env, argv[8], &n)) return enif_make_int(env,9);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
c = (float *) enif_make_new_binary(env, n*c1*h1*w1 * sizeof(float), &c_bin);
d = (float *) enif_make_new_binary(env, n*r2*c2 * sizeof(float), &d_bin);
// random-select
for(i=0;i<n;i++){
r = rand() % n1;
for(j=0;j<c1;j++){
for(k=0;k<h1;k++){
for(l=0;l<w1;l++){
c[IDX4C(i,j,k,l,c1,h1,w1)] = a[IDX4C(r,j,k,l,c1,h1,w1)];
}
}
}
for(j=0;j<c2;j++){
d[IDX2C(i,j,n)] = b[IDX2C(r,j,r2)];
}
}
tuple = enif_make_tuple2(env,c_bin,d_bin);
return(tuple);
}
static ERL_NIF_TERM
is_near1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
int i, n, sw;
float *a, *b;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
// near check
sw = 0;
for(i=0;i<n;i++){
if(fabsf(a[i]) > fabsf(b[i])*1.15 || fabsf(a[i]) < fabsf(b[i])*0.85){
printf("%f %f \r\n", a[i], b[i]);
sw = 1;
}
}
if(sw == 0)
return enif_make_int(env,1); //true
else
return enif_make_int(env,0); //false
}
static ERL_NIF_TERM
is_equal1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin,b_bin;
int i, n;
float *a, *b;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_inspect_binary(env, argv[2], &b_bin )) return enif_make_int(env,3);
a = (float *) a_bin.data;
b = (float *) b_bin.data;
// equal check
for(i=0;i<n;i++){
if(a[i] != b[i]){
return enif_make_int(env,0); //false
}
}
return enif_make_int(env,1); //true
}
static ERL_NIF_TERM
analizer1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
int i, n, id;
float *a;
float max,min,sum;
if (!enif_get_int(env, argv[0], &n)) return enif_make_int(env,1);
if (!enif_inspect_binary(env, argv[1], &a_bin )) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &id)) return enif_make_int(env,3);
a = (float *) a_bin.data;
// near check
for(i=0;i<n;i++){
if(isnan(a[i])){
return enif_make_int(env,9999);
}
if(isinf(a[i])){
return enif_make_int(env,9998);
}
}
//find max min avarage
max = -999999999;
min = 999999999;
sum = 0;
for(i=0;i<n;i++){
if(a[i] > max)
max = a[i];
if(a[i] < min)
min = a[i];
sum = sum+a[i];
}
printf("id max min average\r\n");
printf("%d %f %f %f \r\n", id, max, min, sum/(float)n);
return enif_make_int(env,1);
}
/*
1st arg in_n of tensor
2nd arg in_c of tensor
3rd arg in_h of tensor
4th arg in_w of tensor
5th arg binary of tensor
*/
static ERL_NIF_TERM
standardize1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary a_bin;
ERL_NIF_TERM b_bin;
int in_n,in_c,in_h,in_w,n1,i,c1,h1,w1,count;
float *a,*b;
float sum,average;
if (!enif_get_int(env, argv[0], &in_n)) return enif_make_int(env,1);
if (!enif_get_int(env, argv[1], &in_c)) return enif_make_int(env,2);
if (!enif_get_int(env, argv[2], &in_h)) return enif_make_int(env,3);
if (!enif_get_int(env, argv[3], &in_w)) return enif_make_int(env,4);
if (!enif_inspect_binary(env, argv[4], &a_bin )) return enif_make_int(env,5);
n1 = in_n * in_c * in_h * in_w;
a = (float *) a_bin.data;
b = (float *) enif_make_new_binary(env, n1 * sizeof(float), &b_bin);
for(i=0;i<in_n;i++){
sum = 0.0;
for(c1=0;c1<in_c;c1++){
for(h1=0;h1<in_h;h1++){
for(w1=0;w1<in_w;w1++){
sum = sum + a[IDX4C(i,c1,h1,w1,in_c,in_h,in_w)];
}
}
}
count = in_c * in_h * in_w;
average = sum / (float)count;
for(c1=0;c1<in_c;c1++){
for(h1=0;h1<in_h;h1++){
for(w1=0;w1<in_w;w1++){
b[IDX4C(i,c1,h1,w1,in_c,in_h,in_w)] = a[IDX4C(i,c1,h1,w1,in_c,in_h,in_w)] - average;
}
}
}
}
return(b_bin);
}
// define the array of ErlNifFunc
static ErlNifFunc nif_funcs[] = {
// {erl_function_name, erl_function_arity, c_function}
{"mult1", 6, mult1},
{"new1", 2, new1},
{"new2", 3, new2},
{"new3", 4, new3},
{"new4", 5, new4},
{"rand1", 1, rand1},
{"add1", 3, add1},
{"sub1", 3, sub1},
{"emult1", 3, emult1},
{"transpose1", 3, transpose1},
{"ident1", 1, ident1},
{"activate_sigmoid", 2 ,activate_sigmoid},
{"activate_tanh", 2 , activate_tanh},
{"activate_relu", 2, activate_relu},
{"activate_softmax", 3, activate_softmax},
{"differ_sigmoid", 3, differ_sigmoid},
{"differ_tanh", 3, differ_tanh},
{"differ_relu", 3, differ_relu},
{"smult1", 3, smult1},
{"trace1", 3, trace1},
{"mean_square", 4, mean_square},
{"cross_entropy", 4, cross_entropy},
{"elt1", 5, elt1},
{"set1", 6, set1},
{"add_diff1", 6, add_diff1},
{"add_diff2", 10, add_diff2},
{"average1", 3, average1},
{"sum1", 3, sum1},
{"to_list1", 3, to_list1},
{"to_list2", 4, to_list2},
{"to_list3", 5, to_list3},
{"dropout1", 2 , dropout1},
{"sgd1", 4, sgd1},
{"momentum1", 5, momentum1},
{"adagrad1", 5, adagrad1},
{"rms1", 5, rms1},
{"adam1", 6, adam1},
{"accuracy1", 4, accuracy1},
{"correct1", 4, correct1},
{"pooling1", 7, pooling1},
{"unpooling1", 8, unpooling1},
{"convolute1", 13, convolute1},
{"deconvolute1", 13, deconvolute1},
{"deconvolute2", 13, deconvolute2},
{"gradfilter1", 16, gradfilter1},
{"gradfilter2", 16, gradfilter2},
{"full1", 5, full1},
{"unfull1", 5, unfull1},
{"random_select1", 7, random_select1},
{"random_select2", 9, random_select2},
{"is_near1", 3, is_near1},
{"is_equal1", 3, is_equal1},
{"analizer1", 3, analizer1},
{"standardize1", 5, standardize1}
};
ERL_NIF_INIT(Elixir.Cumatrix, nif_funcs, NULL, NULL, NULL, NULL)