TTrain.cpp 8.64 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 23
/*
* NiuTrans.Tensor - an open-source tensor library
* Copyright (C) 2016-2021
* Natural Language Processing Lab, Northeastern University
* and
* NiuTrans Research
* 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.
*/

/*
* We test XTrain here. It is simple, we design a simple task in that we
xiaotong committed
24 25 26
* make the model to predict an integer D (0-100) from four input integers
* A, B, C and D (0-100). We generate a number of samples with different values
* of A, B, C and D. The gold standard is
xiaotong committed
27
*
xiaotong committed
28
*          D = (int)(sqrt(A * B) + abs(C - D))/2
xiaotong committed
29 30 31 32 33 34 35 36 37 38 39 40 41
*
* Our model is a two-layer feed-forward neural network. It can be treated
* as a classifier rather than a regression model.
*
* $Created by: XIAO Tong (xiaotong@mail.neu.edu.cn) 2021-03-03
*/

#include "TTrain.h"
#include "../tensor/core/CHeader.h"
#include "../tensor/function/FHeader.h"

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

xiaotong committed
42 43
XTensor * tmpTT = NULL;

xiaotong committed
44 45 46 47 48 49
/* genreate the training data file */
void GeneateTTrainData(const char * fileName)
{
    FILE * file = fopen(fileName, "wb");
    CheckNTErrors(file, "Cannot open the file");

xiaotong committed
50
    XPRINT(1, stderr, "[INFO] Generating data ... ");
xiaotong committed
51 52 53 54 55 56 57 58 59 60 61 62

    int sampleNum = MAX_SAMPLE_NUM_IN_TTRAIN;
    int range = MAX_INT_IN_TTRAIN;

    fprintf(file, "%d\n", sampleNum);

    srand(1);

    for (int i = 0; i < sampleNum; i++) {
        int A = (int)(((float)rand() / RAND_MAX) * range);
        int B = (int)(((float)rand() / RAND_MAX) * range);
        int C = (int)(((float)rand() / RAND_MAX) * range);
xiaotong committed
63 64 65
        int D = (int)(((float)rand() / RAND_MAX) * range);
        int E = (int)((sqrt(A * B) + abs(C - D)) / 2);
        fprintf(file, "%d %d %d %d %d\n", A, B, C, D, E);
xiaotong committed
66 67
    }

xiaotong committed
68
    XPRINT2(1, stderr, "%d samples in \"%s\" [DONE]\n", sampleNum, fileName);
xiaotong committed
69 70 71 72 73
    
    fclose(file);
}

/* run the test */
xiaotong committed
74
void TestTrain()
xiaotong committed
75 76 77 78
{
    GeneateTTrainData("ttrain.txt");

    XConfig config;
xiaotong committed
79
    config.Add("dev", -1);
xiaotong committed
80 81 82
    config.Add("lrate", 0.001F);
    config.Add("nstep", 10000);
    config.Add("nepoch", 5);
xiaotong committed
83 84 85 86 87 88 89 90

    TTDataLoader loader;
    loader.SetFileName("ttrain.txt");
    loader.SetBatchSize(config.GetInt("batchsize", TT_BATCH_SIZE));

    TTModel model;
    model.Init(config, -1);

xiaotong committed
91 92
    tmpTT = (XTensor*)model.params[0];

xiaotong committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    XOptimizer optimizer;
    optimizer.Init(config);

    XTrainer trainer;
    trainer.Run(&config, &loader, &model, &optimizer);
}

/*****************************
* data loader
******************************/

/* constructor */
TTDataLoader::TTDataLoader()
{
    fileName = new char[MAX_FILE_NAME_LENGTH];
    file = NULL;
    batchSize = TT_BATCH_SIZE;
}

/* de-constructor */
TTDataLoader::~TTDataLoader()
{
    delete[] fileName;
}

/* set file name */
void TTDataLoader::SetFileName(const char * myFileName)
{
    strcpy(fileName, myFileName);
}

/* set batch size */
void TTDataLoader::SetBatchSize(int myBatchSize)
{
    batchSize = myBatchSize;
}

/* start the process */
bool TTDataLoader::Start()
{
xiaotong committed
133 134
    file = fopen(fileName, "rb");
    CheckNTErrors(file != NULL, "Cannot open the file");
xiaotong committed
135 136 137

    /* skip the first line */
    char * line = new char[MAX_SAMPLE_LINE_LENGTH];
xiaotong committed
138
    fgets(line, MAX_SAMPLE_LINE_LENGTH, file);
xiaotong committed
139 140 141 142 143 144 145 146 147 148 149 150 151
    delete[] line;

    return true;
}

/* end the process */
bool TTDataLoader::End()
{
    fclose(file);

    return true;
}

xiaotong committed
152 153 154 155 156 157
/* 
get a batch of samples 
>> inputs - inputs of the model
>> golds - gold standards
*/
bool TTDataLoader::GetBatchSimple(XList * inputs, XList * golds)
xiaotong committed
158
{
xiaotong committed
159
    CheckNTErrors(file != NULL, "No input file specificed!");
xiaotong committed
160 161
    CheckNTErrors(inputs != NULL && inputs->count >= 1, "Wrong argument!");
    CheckNTErrors(golds != NULL && golds->count >= 1, "Wrong argument!");
xiaotong committed
162

xiaotong committed
163 164
    XTensor * input = (XTensor*)inputs->GetItem(0);
    XTensor * gold = (XTensor*)golds->GetItem(0);
xiaotong committed
165 166 167 168 169 170

    int count = 0;
    int sampleSize = MAX_SAMPLE_SIZE;
    char * line = new char[MAX_SAMPLE_LINE_LENGTH];
    int * inputBatch = new int[batchSize * sampleSize];
    int * goldBatch = new int[batchSize];
xiaotong committed
171
    int A, B, C, D, E;
xiaotong committed
172
    
xiaotong committed
173
    while (fgets(line, MAX_SAMPLE_LINE_LENGTH, file)) {
xiaotong committed
174

xiaotong committed
175
        if (count == batchSize)
xiaotong committed
176 177
            break;

xiaotong committed
178
        if (sscanf(line, "%d %d %d %d %d", &A, &B, &C, &D, &E) < sampleSize + 1) {
xiaotong committed
179 180 181
            ShowNTErrors("Wrong format in the training file!");
        }

xiaotong committed
182 183 184 185 186
        inputBatch[count * sampleSize] = A;
        inputBatch[count * sampleSize + 1] = B;
        inputBatch[count * sampleSize + 2] = C;
        inputBatch[count * sampleSize + 3] = D;
        goldBatch[count] = E;
xiaotong committed
187 188

        count++;
xiaotong committed
189 190
    }

xiaotong committed
191
    if (count > 0) {
xiaotong committed
192
        InitTensor2D(input, count, 4, X_INT);
xiaotong committed
193
        InitTensor2D(gold, count, 1, X_INT);
xiaotong committed
194

xiaotong committed
195
        input->SetData(inputBatch, count * 4);
xiaotong committed
196
        gold->SetData(goldBatch, count);
xiaotong committed
197
    }
xiaotong committed
198 199 200 201 202

    delete[] line;
    delete[] inputBatch;
    delete[] goldBatch;

xiaotong committed
203 204 205 206
    if (count > 0)
        return true;
    else
        return false;
xiaotong committed
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
}

/*****************************
* the neural model
******************************/

/* constructor */
TTModel::TTModel()
{
}

/* de-constructor */
TTModel::~TTModel()
{
}

/* config it */
void TTModel::SetConfig(XConfig &myConfig)
{
    config.CreateFromMe(myConfig);
}

xiaotong committed
229 230 231 232 233
/* 
initialize the model 
>> myConfig - configuration
>> devID - device id
*/
xiaotong committed
234 235
void TTModel::Init(XConfig &myConfig, int devID)
{
xiaotong committed
236
    Clear();
xiaotong committed
237 238
    SetConfig(myConfig);

xiaotong committed
239 240 241
    vSize = MAX_INT_IN_TTRAIN + 1;
    eSize = config.GetInt("esize", TT_EMBEDDING_SIZE);
    hSize = config.GetInt("hsize", TT_HIDDEN_SIZE);
xiaotong committed
242 243

    InitTensor2D(&embeddingW, vSize, eSize, X_FLOAT, devID);
xiaotong committed
244
    InitTensor2D(&hiddenW, MAX_SAMPLE_SIZE * eSize, hSize, X_FLOAT, devID);
xiaotong committed
245
    InitTensor2D(&outputW, hSize, vSize, X_FLOAT, devID);
xiaotong committed
246

xiaotong committed
247 248 249 250
    embeddingW.SetName("embeddingw");
    hiddenW.SetName("hiddenw");
    outputW.SetName("outputw");

xiaotong committed
251 252
    embeddingW.SetDataRand(-0.1F, 0.1F);
    hiddenW.SetDataRand(-0.1F, 0.1F);
xiaotong committed
253
    outputW.SetDataRand(-0.1F, 0.1F);
xiaotong committed
254 255 256 257
    
    AddParam(&embeddingW);
    AddParam(&hiddenW);
    AddParam(&outputW);
xiaotong committed
258 259
}

xiaotong committed
260 261 262 263 264 265
/* 
create the model 
>> devID - device id
>> input - as it is
>> output - as it is
*/
xiaotong committed
266 267 268 269 270 271
void TTModel::Forward(int devID, XTensor * input, XTensor * output)
{
    XTensor embedding;
    XTensor embeddingCat;
    XTensor hidden;

xiaotong committed
272
    /* [e_0, e_1, e_2] = w_e * input(one-hot) */
xiaotong committed
273
    embedding = Gather(embeddingW, *input);
xiaotong committed
274 275

    /* e = merge(e_0, e_1, e_2) */
xiaotong committed
276
    embeddingCat = Merge(embedding, embedding.order - 1, embedding.order - 2);
xiaotong committed
277

xiaotong committed
278 279
    /* h = hardtanh(e * w_h) */
    hidden = HardTanH(MMul(embeddingCat, hiddenW));
xiaotong committed
280

xiaotong committed
281 282
    /* output = Softmax(h * w_o) */
    *output = Softmax(MMul(hidden, outputW), -1);
xiaotong committed
283 284 285 286 287 288 289 290
}

/* clear the model */
void TTModel::Clear()
{
    config.Clear();
}

xiaotong committed
291 292 293 294
/* 
clone the model 
>> devID - device id
*/
xiaotong committed
295 296 297 298 299 300 301 302 303
XModel * TTModel::Clone(int devID)
{
    TTModel * model = new TTModel();
    model->SetConfig(config);
    model->Init(config, devID);

    return model;
}

xiaotong committed
304 305 306 307 308
/* 
run the neural network
>> inputs - inputs of the model
>> outputs - outputs of the model
>> golds - gold standards
309
>> losses - losses of the output respect to the gold standards
xiaotong committed
310
*/
311
bool TTModel::RunSimple(XList * inputs, XList * outputs, XList * golds, XList* losses)
xiaotong committed
312
{
xiaotong committed
313
    //fprintf(stderr, "run simple 0\n");
xiaotong committed
314 315 316
    CheckNTErrors(inputs != NULL && inputs->count >= 1, "Wrong arguments!");
    CheckNTErrors(outputs != NULL && outputs->count >= 1, "Wrong arguments!");
    CheckNTErrors(golds != NULL && golds->count >= 1, "Wrong arguments!");
317
    CheckNTErrors(losses != NULL && losses->count >= 1, "Wrong arguments!");
xiaotong committed
318

xiaotong committed
319 320 321
    XTensor * input = (XTensor*)inputs->GetItem(0);
    XTensor * output = (XTensor*)outputs->GetItem(0);
    XTensor * gold = (XTensor*)golds->GetItem(0);
322
    XTensor * loss = (XTensor*)losses->GetItem(0);
xiaotong committed
323
    XTensor goldOneHot;
xiaotong committed
324 325 326

    XNet net;

xiaotong committed
327
    /* create the neural network and run it */
xiaotong committed
328 329
    Forward(devID, input, output);

xiaotong committed
330
    /* gold standard in ong-hot representaiton */
xiaotong committed
331 332
    goldOneHot = IndexToOnehot(*gold, vSize, 0.0F);

xiaotong committed
333
    int * dims = new int[goldOneHot.order];
xiaotong committed
334 335 336 337 338
    for (int i = 0; i < goldOneHot.order - 2; i++)
        dims[i] = goldOneHot.GetDim(i);
    dims[goldOneHot.order - 2] = goldOneHot.GetDim(goldOneHot.order - 1);
    goldOneHot.Reshape(goldOneHot.order - 1, dims);

xiaotong committed
339
    /* loss */
340
    *loss = CrossEntropy(*output, goldOneHot);
xiaotong committed
341

xiaotong committed
342
    /* back-propagation */
343
    net.Backward(*loss);
xiaotong committed
344

xiaotong committed
345
    delete[] dims;
xiaotong committed
346
    
xiaotong committed
347
    //fprintf(stderr, "run simple 1\n");
xiaotong committed
348

xiaotong committed
349 350 351 352
    return true;
}

}