SetData.cpp 18.4 KB
Newer Older
xiaotong committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * NiuTrans.Tensor - an open-source tensor library
 * Copyright (C) 2018, Natural Language Processing Lab, Northestern University.
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Created by: XIAO Tong (email: xiaotong@mail.neu.edu.cn) 2018-05-08
 */

23
#include <math.h>
xiaotong committed
24
#include "SetData.h"
25 26
#include "SetData.cuh"
#include "../../XUtility.h"
27
#include "../movement/CopyValues.h"
xiaotong committed
28 29 30 31 32 33 34 35 36 37 38 39 40

#if !defined( WIN32 ) && !defined( _WIN32 )
    #include "sys/time.h"
    #include "time.h"
    #include "iconv.h"
#else
    #include "time.h"
    #include "windows.h"
    #include "process.h"
#endif

namespace nts{ // namespace nts(NiuTrans.Tensor)

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
/*
Fills the input Tensor or Variable with values according to the method described in 
"Understanding the difficulty of training deep feedforward neural networks" - Glorot, X. & Bengio, Y. (2010), 
using a uniform distribution. The resulting tensor will have values sampled from :math:`U(-a, a)` 
where :math:`a = gain \times \sqrt{2 / (fan\_in + fan\_out)} \times \sqrt{3}`. Also known as Glorot initialisation.

>> tensor - the tensor whose data array would be initialized
>> gain - an optional scaling factor
*/
void _SetDataFanInOut(XTensor * tensor, DTYPE gain)
{
    CheckNTErrors(tensor->dataType == X_FLOAT, "the tensor must be in X_FLOAT!");
    CheckNTErrors(tensor->order >= 2, "the tensor dimension must be no less than 2!");

    int fanIn = 1;
    int fanOut = 1;

    int order = tensor->order;
    if (order == 2) {
        fanIn = tensor->dimSize[1];
        fanOut = tensor->dimSize[0];
    }
    else {
        int numInputFmaps = tensor->dimSize[1];
        int numOutputFmaps = tensor->dimSize[0];
        int receptiveFieldSize = 0;
        for (int i = 2; i < order; i++)
            receptiveFieldSize += tensor->dimSize[i];
        fanIn = numInputFmaps * receptiveFieldSize;
        fanOut = numOutputFmaps * receptiveFieldSize;
    }

73 74 75
    DTYPE std = gain * (float)sqrt(2.0 / (fanIn + fanOut));
    DTYPE a = (DTYPE)sqrt(3.0F) * std;
    tensor->SetDataRand(-a, a);
76
    //_SetDataRand(tensor, -finfout, finfout);
77 78
}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
/* 
generate data items with a fixed value p 
>> tensor - the tensor whose data array would be initialized
>> p - pointer to the number for initializing the tensor
*/
void _SetDataFixed(XTensor * tensor, void * valuePointer)
{
    int num = tensor->unitNum;

    if(tensor->dataType == X_INT){
        int p = *(int*)valuePointer;
        if(tensor->devID < 0){
            int * d = (int*)tensor->data;
            if(num % 4 == 0){
                for(int i = 0; i < num; i += 4){
                    d[i] = p;
                    d[i + 1] = p;
                    d[i + 2] = p;
                    d[i + 3] = p;
                }
            }
            else{
                for(int i = 0; i < num; i++)
                    d[i] = p;
            }
        }
        else{
#ifdef USE_CUDA
107
            _CudaSetDataFixedInt(tensor, p);
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
#endif
        }
    }
    else if(tensor->dataType == X_FLOAT){
        float p = *(float*)valuePointer;
        if(tensor->devID < 0){
            float * d = (float*)tensor->data;
            if(num % 4 == 0){
                for(int i = 0; i < num; i += 4){
                    d[i] = p;
                    d[i + 1] = p;
                    d[i + 2] = p;
                    d[i + 3] = p;
                }
            }
            else{
                for(int i = 0; i < num; i++)
                    d[i] = p;
            }
        }
        else{
#ifdef USE_CUDA
130
            _CudaSetDataFixedFloat(tensor, p);
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
#endif
        }
    }
    else if(tensor->dataType == X_DOUBLE){
        double p = *(double*)valuePointer;
        if(tensor->devID < 0){
            double * d = (double*)tensor->data;
            if(num % 4 == 0){
                for(int i = 0; i < num; i += 4){
                    d[i] = p;
                    d[i + 1] = p;
                    d[i + 2] = p;
                    d[i + 3] = p;
                }
            }
            else{
                for(int i = 0; i < num; i++)
                    d[i] = p;
            }
        }
        else{
#ifdef USE_CUDA
153
            _CudaSetDataFixedDouble(tensor, p);
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
#endif
        }
    }
    else{
        ShowNTErrors("TODO");
    }
}

/* 
generate data items with a fixed value p (in default type) 
>> tensor - the tensor whose data array would be initialized
>> p - number in default type
*/
void SetDataFixed(XTensor &tensor, DTYPE p)
{
    _SetDataFixed(&tensor, &p);
}
xiaotong committed
171 172 173 174 175 176 177 178 179 180 181
    
/*
generate data items with a fixed value p (in integer)
>> tensor - the tensor whose data array would be initialized
>> p - an integer
*/
void SetDataFixedInt(XTensor &tensor, int p)
{
    CheckNTErrors(tensor.dataType == X_INT, "An integer tensor is required!");
    _SetDataFixed(&tensor, &p);
}
182 183 184 185 186 187 188 189

/* 
generate data items with a fixed value p (in integer) 
>> tensor - the tensor whose data array would be initialized
>> p - an int-valued number
*/
void _SetDataFixedInt(XTensor * tensor, int p)
{
190
    CheckNTErrors(tensor->dataType == X_INT, "the tensor must be in X_INT!");
191 192 193 194 195 196 197 198 199 200 201 202 203 204

    if(p == 0)
        tensor->SetZeroAll();
    else
        _SetDataFixed(tensor, &p);
}

/*
generate data items with a fixed value p (in float) 
>> tensor - the tensor whose data array would be initialized
>> p - a float-valued number
*/
void _SetDataFixedFloat(XTensor * tensor, float p)
{
205
    CheckNTErrors(tensor->dataType == X_FLOAT, "the tensor must be in X_FLOAT!");
206 207 208 209 210 211 212 213 214 215 216 217 218 219

    if(p == 0)
        tensor->SetZeroAll();
    else
        _SetDataFixed(tensor, &p);
}

/* 
generate data items with a fixed value p (in double) 
>> tensor - the tensor whose data array would be initialized
>> p - a double-valued number
*/
void _SetDataFixedDouble(XTensor * tensor, double p)
{
220
    CheckNTErrors(tensor->dataType == X_DOUBLE, "the tensor must be in X_DOUBLE!");
221 222 223 224 225 226 227

    if(p == 0)
        tensor->SetZeroAll();
    else
        _SetDataFixed(tensor, &p);
}

xuchen committed
228
/* 
xiaotong committed
229 230 231 232 233 234 235 236 237 238 239 240
generate data items with a fixed value p only if 
the condition entry is non-zero 
>> tensor - the tensor whose data array would be initialized
>> condition - the condition tensor whose entries would be checked
               for set the corresponding entries in "tensor"
>> p - a given value
*/
void _SetDataFixedCond(XTensor * tensor, XTensor * condition, DTYPE p)
{
    int num = tensor->unitNum;

    CheckNTErrors(num == condition->unitNum, "Wrong size of the condition tensor!");
241
    CheckNTErrors(condition->unitSize == sizeof(float), "TODO!");
xiaotong committed
242 243 244 245 246 247 248 249 250 251 252

    if(tensor->dataType == DEFAULT_DTYPE){
        if(tensor->devID < 0){
            DTYPE * data = (DTYPE*)tensor->data;
            DTYPE * cond = (DTYPE*)condition->data;
            for(int i = 0; i < num; i++){
                if(cond[i] != 0)
                    data[i] = p;
            }
        }
        else{
253
#ifdef USE_CUDA
xiaotong committed
254
            _CudaSetDataFixedCondFloat(tensor, condition, p);
255 256 257
#else
            ShowNTErrors("Please specify USE_CUDA and recompile the code");
#endif
xiaotong committed
258
        }
259 260
    }
    else{
xiaotong committed
261
        ShowNTErrors("the tensor should be in integer typed!");
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    }
}

/* 
generate data items with a fixed value p only if 
the condition entry is non-zero 
>> tensor - the tensor whose data array would be initialized
>> condition - the condition tensor whose entries would be checked
               for set the corresponding entries in "tensor"
>> p - a given value
*/
void _SetDataFixedCondInt(XTensor * tensor, XTensor * condition, int p)
{
    int num = tensor->unitNum;

    CheckNTErrors(num == condition->unitNum, "Wrong size of the condition tensor!");
    CheckNTErrors(condition->unitSize == sizeof(float), "TODO!");

    if(tensor->dataType == DEFAULT_DTYPE){
        if(tensor->devID < 0){
            int * data = (int*)tensor->data;
            int * cond = (int*)condition->data;
            for(int i = 0; i < num; i++){
                if(cond[i] != 0)
                    data[i] = p;
            }
        }
        else{
290
#ifdef USE_CUDA
291
            _CudaSetDataFixedCondInt(tensor, condition, p);
292 293 294
#else
            ShowNTErrors("Please specify USE_CUDA and recompile the code");
#endif
295
        }
xiaotong committed
296 297 298 299 300 301 302
    }
    else{
        ShowNTErrors("TODO!");
    }
}

/* 
xuchen committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
set data items along with a given dimension (and keep the remaining items unchanged) 
>> tensor - the tensor whose data array would be initialized
>> beg - the beginning position
>> len - length along with the given dimension
>> dim - the dimension along which we set the data
e.g., given a 3 * 3 tensor 
      1 2 3
      4 5 6
      7 8 9
      when beg = 1, len = 1, dim = 0 and p = 0, we have
      1 2 3
      0 0 0
      7 8 9
      i.e., we set all entries of row 1 to 0
*/
void _SetDataDim(XTensor * tensor, int beg, int len, int dim, DTYPE p)
{
    int n = tensor->order;

    CheckNTErrors(tensor->dataType == DEFAULT_DTYPE, "TODO!");
323
    CheckNTErrors(dim < n && dim >= 0, "Illegal dimension!");
xuchen committed
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
    CheckNTErrors(beg >= 0 && beg < tensor->GetDim(dim), "Illegal beginning position!");
    CheckNTErrors(beg + len >= 0 && beg + len < tensor->GetDim(dim), "Illegal length!");
    
    if(tensor->devID < 0){
        int stride = 1;
        int blockSize = 1;
        int blockNum  = 1;
        for(int i = n - 1; i > dim; i--){
            stride *= tensor->GetDim(i);
        }
        blockSize = stride * tensor->GetDim(dim);
        blockNum = tensor->unitNum / blockSize;

        int l = len * stride;

        for(int i = 0; i < blockNum; i++){
            DTYPE * d = (DTYPE*)tensor->data + blockSize * i + beg * stride;    
            for(int j = 0; j < l; j++)
                d[j] = p;
        }
    }
    else{
#ifdef USE_CUDA
        _CudaSetDataDim(tensor, beg, len, dim, p);
#endif
    }
}

/* 
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
modify data items along with a given index and dimension (and keep the remaining items unchanged) 
>> source - the tensor whose data array would be modified
>> modify - the tensor whose data array would be used to modify the source tensor
>> dim - the dimension along which we modify the tensor
>> index - index of the given dimension
e.g., given a source tensor (3, 3)
      1 2 3
      4 5 6
      7 8 9
      given a modified tensor (3)
      1 2 3
      when dim = 0, index = 1, we have
      1 2 3
      1 2 3
      7 8 9
      i.e., we set entries of row 1 to {1, 2, 3}
*/
void _SetDataIndexed(XTensor * source, XTensor * modify, int dim, int index)
{
    int order = source->order;
    int size = source->GetDim(dim);

    CheckNTErrors(source->dataType == DEFAULT_DTYPE, "TODO!");
    CheckNTErrors(dim >= 0 && dim < order, "Illegal dimension!");
    CheckNTErrors(index >= 0 && index < size, "Illegal index!");
    
    for(int i = 0; i < order - 1; i++){
        if(i < dim){
            CheckNTErrors(modify->GetDim(i) == source->GetDim(i), "Illegal dimension!");
        }
        else if(i >= dim){
            CheckNTErrors(modify->GetDim(i) == source->GetDim(i+1), "Illegal dimension!");
        }
    }

    if(source->devID < 0 && modify->devID < 0){
        int stride = 1;
        int blockSize = 1;
        int blockNum  = 1;

        for(int i = order - 1; i > dim; i--){
            stride *= source->GetDim(i);
        }

        blockSize = stride * source->GetDim(dim);
        blockNum = source->unitNum / blockSize;

        for(int i = 0; i < blockNum; i++){
            DTYPE * d = (DTYPE*)source->data + blockSize * i + index * stride;
            DTYPE * p = (DTYPE*)modify->data + stride * i;
            for(int j = 0; j < stride; j++)
                d[j] = p[j];
        }
    }
    else if(source->devID >= 0 && modify->devID >= 0) {
#ifdef USE_CUDA
        _CudaSetDataIndexed(source, modify, dim, index);
#else
        ShowNTErrors("Please specify USE_CUDA and recompile the code!");
#endif
    }
    else{
        ShowNTErrors("TODO!");
    }
}

/* 
xuchen committed
420 421 422 423
generate data as lower triangular matrics for last two dimensions 
>> tensor - the tensor whose data to be set
>> p - the value for each entry of the lower triangular matrics
>> shift - the offset from diagonal
424
e.g., for a 3 * 3 tensor, 
xuchen committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
      when p = 1 ans shift = 0, we have
      1 0 0
      1 1 0
      1 1 1
      when p = 2 and shift = -1, we have
      0 0 0
      2 0 0
      2 2 0
*/
void _SetDataLowTri(XTensor * tensor, DTYPE p, int shift)
{
    int n = tensor->order;

    CheckNTErrors(tensor->dataType == DEFAULT_DTYPE, "TODO!");
    CheckNTErrors(n >= 2, "The tensor must have a order no less than 2!");
    CheckNTErrors(tensor->GetDim(n - 1) == tensor->GetDim(n - 2), 
                 "The last two dimensions must be of the same size!");

    if(tensor->devID < 0){
        int l = tensor->GetDim(-1);
        int blockNum = 1;
        int blockSize = l * l;
        for(int i = 0; i < n - 2; i++)
            blockNum *= tensor->GetDim(i);

        for(int i = 0; i < blockNum; i++){
            DTYPE * d = (DTYPE*)tensor->data + i * blockSize;
            for(int row = 0; row < l; row++){
                for(int col = 0; col <= row + shift; col++){
                    d[row * l + col] = p;
                }
                for(int col = MAX(0, row + shift + 1); col < l; col++){
                    d[row * l + col] = 0;
                }
            }
        }
    }
    else{
#ifdef USE_CUDA
        _CudaSetDataLowTri(tensor, p, shift);
#endif
    }
}

xiaotong committed
469
/*
470
generate data items with a uniform distribution in [lower, upper]
xiaotong committed
471
>> tensor - the tensor whose data array would be initialized
472 473
>> lower - lower value of the range
>> upper - upper value of the range
xiaotong committed
474
*/
475
void _SetDataRand(const XTensor * tensor, DTYPE lower, DTYPE upper)
xiaotong committed
476
{
477
    CheckNTErrors(upper > lower, "the high value must be greater than low value!");
478

xiaotong committed
479 480 481
    if(tensor == NULL)
        return;
    
482
    /* CPU code */
xiaotong committed
483
    if(tensor->devID < 0){
484
        DTYPE variance = upper - lower;
xiaotong committed
485 486 487 488
        
        if(tensor->dataType == X_FLOAT){
            float * d = (float*)tensor->data;
            for(int i = 0; i < tensor->unitNum; i++){
489
                d[i] = variance * ((float)rand()/RAND_MAX) + lower;
xiaotong committed
490 491 492 493 494
            }
        }
        else if(tensor->dataType == X_DOUBLE){
            double * d = (double*)tensor->data;
            for(int i = 0; i < tensor->unitNum; i++){
495
                d[i] = variance * ((double)rand()/RAND_MAX) + lower;
xiaotong committed
496 497 498 499 500 501
            }
        }
        else{
            ShowNTErrors("TODO");
        }
    }
liyinqiao committed
502 503 504 505 506
    /* 
    GPU code
    The trick here is that initialize the data on a temperary tensor on CPU.
    The CPU data is then copied to GPU.
    TODO: generate data points on GPUs straightforwardly.
xiaotong committed
507 508
    */
    else{
509
#ifdef USE_CUDA
510
        _CudaSetDataRand(tensor, lower, upper);
511 512 513 514 515
#endif
        //XTensor * t2 = NewTensor(tensor->order, tensor->dimSize, tensor->dataType, tensor->denseRatio, -1);
        //_SetDataRand(t2, low, high);
        //_CopyValues(t2, tensor);
        //delete t2;
xiaotong committed
516 517
    }
}
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550

/* 
generate data items with a uniform distribution in [lower, upper] and set
the item to a pre-defined value if the item >= p, set the item to 0 otherwise
>> tensor - the tensor whose data array would be initialized
>> lower - lower value of the range
>> upper - upper value of the range
>> p - the threshold
>> value - the value we intend to assign to the item
*/
void _SetDataRandP(const XTensor * tensor, DTYPE lower, DTYPE upper, DTYPE p, DTYPE value)
{
    CheckNTErrors(tensor->dataType == DEFAULT_DTYPE, "TODO");

    if (tensor->devID < 0) {
        _SetDataRand(tensor, lower, upper);

        DTYPE * data = (DTYPE*)tensor->data;
        for (int i = 0; i < tensor->unitNum; i++) {
            if (data[i] >= p)
                data[i] = value;
            else
                data[i] = 0;
        }
    }
    else {
#ifdef USE_CUDA
        _CudaSetDataRandP(tensor, lower, upper, p, value);
#else
        ShowNTErrors("Please recompile the code by specifying USE_CUDA");
#endif // USE_CUDA
    }
}
xiaotong committed
551
    
552 553
/*
generate data items with a normal distribution with specified mean and standard deviation 
xiaotong committed
554
>> tensor - the tensor that keeps the data
555 556 557 558 559 560 561 562 563
>> mean - mean or expectation of the distribution
>> standardDeviation - standard deviation of the distribution
*/
void _SetDataRandN(XTensor * tensor, DTYPE mean, DTYPE standardDeviation)
{
    // TODO: rewrite it and add cuda code!!!!!!!
    tensor->SetDataRandn(mean, standardDeviation);
}

xiaotong committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
/* 
set the data with an array of offsets 
>> tensor - the tensor that keeps the data
>> offsets - offset for each data item
>> num - number of the data items
>> value - value of the data items
*/
void _SetDataWithOffset(XTensor * tensor, MTYPE * offsets, DTYPE value, MTYPE num)
{
    CheckNTErrors(tensor->dataType == X_FLOAT, "Data type is incorrect!");

    if (tensor->devID < 0) {
        DTYPE * d = (DTYPE*)tensor->data;
        for (int i = 0; i < num; i++) {
            d[offsets[i]] = value;
        }
    }
    else {
#ifdef USE_CUDA
        XMem * mem = tensor->mem;
        MTYPE size = num * sizeof(MTYPE);
xiaotong committed
585
        MTYPE * offsetsCuda = mem != NULL ? (MTYPE*)mem->AllocBuf(mem->devID, size) : (MTYPE*)XMemAlloc(tensor->devID, size);
xiaotong committed
586 587 588 589 590 591 592
        XMemCopy(offsetsCuda, tensor->devID, offsets, -1, num * sizeof(MTYPE));

        _CudaSetDataWithOffset(tensor, offsetsCuda, value, num);
        
        if (mem != NULL)
            mem->ReleaseBuf(mem->devID, size);
        else
xiaotong committed
593
            XMemFree(tensor->devID, offsetsCuda);
xiaotong committed
594 595 596 597 598 599 600 601 602 603 604 605 606
#else
        ShowNTErrors("Please recompile the code with USE_CUDA");
#endif
    }
}

/* 
set the data with an array of values 
>> tensor - the tensor that keeps the data
>> offsets - offset for each data item
>> values - value for each data item
>> num - number of the data items
*/
607
void _SetDataWithOffsetAndValue(XTensor * tensor, MTYPE * offsets, void * values, MTYPE num)
xiaotong committed
608
{
609 610 611 612 613 614 615 616 617 618 619 620
    if (tensor->devID < 0) {
        for (int i = 0; i < num; i++) {
            if (tensor->dataType == X_INT)
                *((int *)tensor->data + offsets[i]) = *((int *)values + i);
            else if (tensor->dataType == X_FLOAT)
                *((float *)tensor->data + offsets[i]) = *((float *)values + i);
            else 
                ShowNTErrors("TO DO!!!");
        }
    }
    else {
#ifdef USE_CUDA
621 622 623
        if(tensor->devID >= 0) {
            _CudaSetDataWithOffsetAndValue(tensor, offsets, values, num);
            return;
624 625 626 627 628
        }
#else
        ShowNTErrors("Please recompile the code with USE_CUDA");
#endif
    }
xiaotong committed
629 630
}

xiaotong committed
631 632
} // namespace nts(NiuTrans.Tensor)