日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TransE代码实践(很详细)

發布時間:2023/12/2 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TransE代码实践(很详细) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

TranE是一篇Bordes等人2013年發表在NIPS上的文章提出的算法。它的提出,是為了解決多關系數據(multi-relational data)的處理問題。TransE的直觀含義,就是TransE基于實體和關系的分布式向量表示,將每個三元組實例(head,relation,tail)中的關系relation看做從實體head到實體tail的翻譯,通過不斷調整h、r和t(head、relation和tail的向量),使(h + r) 盡可能與 t 相等,即 h + r = t。
這篇文章主要用來記錄下TransE的代碼。代碼難點有兩點,一是生成隨機數的過程相對復雜一些;第二是生成偽數據時的流程即corrupt_head,其他照著主函數的執行流程應該都沒問題。附一張corrupt_head執行樣例。

#include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> #include <ctime> #include <string> #include <algorithm> #include <pthread.h> #include <iostream> #include <sstream>using namespace std;const float pi = 3.141592653589793238462643383;int transeThreads = 8; int transeTrainTimes = 1000; int nbatches = 10; int dimension = 50; float transeAlpha = 0.001; float margin = 1;string inPath = "../../"; string outPath = "../../";int *lefHead, *rigHead; int *lefTail, *rigTail;struct Triple {int h, r, t; };Triple *trainHead, *trainTail, *trainList;struct cmp_head {bool operator()(const Triple &a, const Triple &b) {return (a.h < b.h)||(a.h == b.h && a.r < b.r)||(a.h == b.h && a.r == b.r && a.t < b.t);} };struct cmp_tail {bool operator()(const Triple &a, const Triple &b) {return (a.t < b.t)||(a.t == b.t && a.r < b.r)||(a.t == b.t && a.r == b.r && a.h < b.h);} };/*There are some math functions for the program initialization.*/ // 轉換數組next_random中index為id的值 unsigned long long *next_random; // 轉換next_random索引為id的值并返回 unsigned long long randd(int id) {next_random[id] = next_random[id] * (unsigned long long)25214903917 + 11;return next_random[id]; }int rand_max(int id, int x) { //小于x的隨機數int res = randd(id) % x;while (res<0)res+=x;return res; }float rand(float min, float max) {return min + (max - min) * rand() / (RAND_MAX + 1.0); }// 返回x的概率密度函數 float normal(float x, float miu,float sigma) {return 1.0/sqrt(2*pi)/sigma*exp(-1*(x-miu)*(x-miu)/(2*sigma*sigma)); }//返回一個大于或等于均值miu的概率密度并且屬于[min,max]的數 float randn(float miu,float sigma, float min ,float max) {float x, y, dScope;do {x = rand(min,max);y = normal(x,miu,sigma);dScope=rand(0.0,normal(miu,miu,sigma));} while (dScope > y);return x; } // 向量標準化 void norm(float * con) {float x = 0;for (int ii = 0; ii < dimension; ii++)x += (*(con + ii)) * (*(con + ii));x = sqrt(x);if (x>1)for (int ii=0; ii < dimension; ii++)*(con + ii) /= x; }/*Read triples from the training file.*/int relationTotal, entityTotal, tripleTotal; float *relationVec, *entityVec; float *relationVecDao, *entityVecDao;// 將實體id 關系id 三元組導入、初始化要訓練的向量 void init() {FILE *fin;int tmp;fin = fopen((inPath + "relation2id.txt").c_str(), "r"); //fopen創建或打開,c_str()返回一個指向正規C字符串的臨時的指針常量tmp = fscanf(fin, "%d", &relationTotal); //獲取總的total數fclose(fin);//構建關系向量relationVec = (float *)calloc(relationTotal * dimension, sizeof(float));//分配realtionTotal*dimensionfor (int i=0;i<relationTotal; i++) {for (int ii=0;ii<dimension; ii++)relationVec[i*dimension+ii] = randn(0,1.0/dimension,-6/sqrt(dimension),6/sqrt(dimension));//(miu,sigma,min,max)}fin = fopen((inPath + "entity2id.txt").c_str(), "r");tmp = fscanf(fin,"%d",&entityTotal);fclose(fin);entityVec = (float *)calloc(entityTotal * dimension, sizeof(float));for (int i=0;i<entityTotal;i++) {for (int ii=0;ii<dimension;ii++)entityVec[i * dimension + ii] = randn(0, 1.0 / dimension, -6 / sqrt(dimension), 6 / sqrt(dimension));norm(entityVec+i*dimension); // 單個entity向量標準化}fin = fopen((inPath + "triple2id.txt").c_str(), "r");tmp = fscanf(fin, "%d", &tripleTotal);trainHead = (Triple *)calloc(tripleTotal, sizeof(Triple));trainTail = (Triple *)calloc(tripleTotal, sizeof(Triple));trainList = (Triple *)calloc(tripleTotal, sizeof(Triple));tripleTotal = 0;//trainlist存儲三元組,復制給 trainHead和trainTailwhile (fscanf(fin, "%d", &trainList[tripleTotal].h) == 1) {tmp = fscanf(fin, "%d", &trainList[tripleTotal].t);tmp = fscanf(fin, "%d", &trainList[tripleTotal].r);trainHead[tripleTotal].h = trainList[tripleTotal].h;trainHead[tripleTotal].t = trainList[tripleTotal].t;trainHead[tripleTotal].r = trainList[tripleTotal].r;trainTail[tripleTotal].h = trainList[tripleTotal].h;trainTail[tripleTotal].t = trainList[tripleTotal].t;trainTail[tripleTotal].r = trainList[tripleTotal].r;tripleTotal++;}fclose(fin);//按照head和tail排序sort(trainHead, trainHead + tripleTotal, cmp_head());sort(trainTail, trainTail + tripleTotal, cmp_tail());lefHead = (int *)calloc(entityTotal, sizeof(int));rigHead = (int *)calloc(entityTotal, sizeof(int));lefTail = (int *)calloc(entityTotal, sizeof(int));rigTail = (int *)calloc(entityTotal, sizeof(int));memset(rigHead, -1, sizeof(int)*entityTotal); //初始化memset(rigTail, -1, sizeof(int)*entityTotal);for (int i=1;i<tripleTotal;i++) {if (trainTail[i].t != trainTail[i - 1].t) {rigTail[trainTail[i - 1].t] = i - 1; // 將索引為i-1的t的值置為i-1,意思TrainTail[i-1]的值的終止點lefTail[trainTail[i].t] = i; // 將索引為i的t的值置為i,意思是TrainTail[i]與左側值不同,意思TrainTail[i]的值的終止點}if (trainHead[i].h != trainHead[i - 1].h) {rigHead[trainHead[i - 1].h] = i - 1;lefHead[trainHead[i].h] = i;}}rigHead[trainHead[tripleTotal - 1].h] = tripleTotal - 1;rigTail[trainTail[tripleTotal - 1].t] = tripleTotal - 1;relationVecDao = (float*)calloc(dimension * relationTotal, sizeof(float));entityVecDao = (float*)calloc(dimension * entityTotal, sizeof(float)); }/*Training process of transE.*/int transeLen; int transeBatch; float res;// 計算距離 d(e1-e2-r)=sum(|e1-e2-r|) float calc_sum(int e1, int e2, int rel) {float sum=0;int last1 = e1 * dimension;int last2 = e2 * dimension;int lastr = rel * dimension;for (int ii=0; ii < dimension; ii++) {// 從entityVec取值計算losssum += fabs(entityVec[last2 + ii] - entityVec[last1 + ii] - relationVec[lastr + ii]);}return sum; } // 更新梯度,正樣本試圖縮小梯度,負樣本試圖增大梯度 void gradient(int e1_a, int e2_a, int rel_a, int e1_b, int e2_b, int rel_b) {int lasta1 = e1_a * dimension;int lasta2 = e2_a * dimension;int lastar = rel_a * dimension;int lastb1 = e1_b * dimension;int lastb2 = e2_b * dimension;int lastbr = rel_b * dimension;for (int ii=0; ii < dimension; ii++) {float x;x = (entityVec[lasta2 + ii] - entityVec[lasta1 + ii] - relationVec[lastar + ii]);if (x > 0)x = -transeAlpha;elsex = transeAlpha;relationVec[lastar + ii] -= x;entityVec[lasta1 + ii] -= x;entityVec[lasta2 + ii] += x;x = (entityVec[lastb2 + ii] - entityVec[lastb1 + ii] - relationVec[lastbr + ii]);if (x > 0)x = transeAlpha;elsex = -transeAlpha;relationVec[lastbr + ii] -= x;entityVec[lastb1 + ii] -= x;entityVec[lastb2 + ii] += x;} }// 計算距離并更新梯度 void train_kb(int e1_a, int e2_a, int rel_a, int e1_b, int e2_b, int rel_b) {float sum1 = calc_sum(e1_a, e2_a, rel_a);float sum2 = calc_sum(e1_b, e2_b, rel_b);// 不滿足條件則需要更新梯度if (sum1 + margin > sum2) {res += margin + sum1 - sum2;gradient(e1_a, e2_a, rel_a, e1_b, e2_b, rel_b);} } // 根據相同的h返回一個假的樣本t,獲取三元組中相同h對應的r int corrupt_head(int id, int h, int r) {int lef, rig, mid, ll, rr;lef = lefHead[h] - 1;rig = rigHead[h];while (lef + 1 < rig) { //則該值不止一個mid = (lef + rig) >> 1; // 除2if (trainHead[mid].r >= r) rig = mid; elselef = mid;}ll = rig; // r值對應的indexlef = lefHead[h];rig = rigHead[h] + 1;while (lef + 1 < rig) {mid = (lef + rig) >> 1;if (trainHead[mid].r <= r) lef = mid; elserig = mid;}rr = lef;int tmp = rand_max(id, entityTotal - (rr - ll + 1)); //生成一個小于entityTotal - (rr - ll + 1)的隨機數if (tmp < trainHead[ll].t) return tmp; //小于初始t 直接返回if (tmp > trainHead[rr].t - rr + ll - 1) return tmp + rr - ll + 1; //lef = ll, rig = rr + 1;while (lef + 1 < rig) {mid = (lef + rig) >> 1;if (trainHead[mid].t - mid + ll - 1 < tmp)lef = mid;elserig = mid;}return tmp + lef - ll + 1; }int corrupt_tail(int id, int t, int r) {int lef, rig, mid, ll, rr;lef = lefTail[t] - 1;rig = rigTail[t];while (lef + 1 < rig) {mid = (lef + rig) >> 1;if (trainTail[mid].r >= r) rig = mid; elselef = mid;}ll = rig;lef = lefTail[t];rig = rigTail[t] + 1;while (lef + 1 < rig) {mid = (lef + rig) >> 1;if (trainTail[mid].r <= r) lef = mid; elserig = mid;}rr = lef;int tmp = rand_max(id, entityTotal - (rr - ll + 1));if (tmp < trainTail[ll].h) return tmp;if (tmp > trainTail[rr].h - rr + ll - 1) return tmp + rr - ll + 1;lef = ll, rig = rr + 1;while (lef + 1 < rig) {mid = (lef + rig) >> 1;if (trainTail[mid].h - mid + ll - 1 < tmp)lef = mid;elserig = mid;}return tmp + lef - ll + 1; } // 接受線程id作為輸入,調用corrupt生成正負樣本,train_kb進行訓練 void* transetrainMode(void *con) {int id;id = (unsigned long long)(con); //補0即可next_random[id] = rand();for (int k = transeBatch / transeThreads; k >= 0; k--) { // 一個batch訓練的樣本數按照線程均分int j;// 生成一個樣本隨機的樣本idint i = rand_max(id, transeLen); // i為生成的隨機數int pr = 500; //一半的概率1/2決定生成 偽head tailif (randd(id) % 1000 < pr) {// 選擇正、負樣本作為訓練輸入j = corrupt_head(id, trainList[i].h, trainList[i].r);train_kb(trainList[i].h, trainList[i].t, trainList[i].r, trainList[i].h, j, trainList[i].r);} else {j = corrupt_tail(id, trainList[i].t, trainList[i].r);train_kb(trainList[i].h, trainList[i].t, trainList[i].r, j, trainList[i].t, trainList[i].r);}norm(relationVec + dimension * trainList[i].r); // 標準化norm(entityVec + dimension * trainList[i].h);norm(entityVec + dimension * trainList[i].t);norm(entityVec + dimension * j);}pthread_exit(NULL); }// 創建線程執行 調用transetrainMode 模型訓練 void train_transe(void *con) {transeLen = tripleTotal;transeBatch = transeLen / nbatches; // 一個batch的樣本大小next_random = (unsigned long long *)calloc(transeThreads, sizeof(unsigned long long)); // 根據線程數創建表示線程的數組for (int epoch = 0; epoch < transeTrainTimes; epoch++) {res = 0;// 一個epoch包含nbatches個batch,每個batch再按線程劃分for (int batch = 0; batch < nbatches; batch++) {pthread_t *pt = (pthread_t *)malloc(transeThreads * sizeof(pthread_t)); // 表示線程id,可以認為unsigned long int類型for (long a = 0; a < transeThreads; a++)pthread_create(&pt[a], NULL, transetrainMode, (void*)a); // 創建線程(指向線程標識符的指針,線程屬性,運行函數的地址,運行函數的參數)for (long a = 0; a < transeThreads; a++)pthread_join(pt[a], NULL); //以阻塞的方式等待thread指定的線程結束,主線程等待直到等待的線程結束free(pt);}printf("epoch %d %f\n", epoch, res);} }/*save result*/void out_transe() {stringstream ss;ss << dimension;string dim = ss.str();FILE* f2 = fopen((outPath + "TransE_relation2vec_" + dim + ".vec").c_str(), "w");FILE* f3 = fopen((outPath + "TransE_entity2vec_" + dim + ".vec").c_str(), "w");for (int i=0; i < relationTotal; i++) {int last = dimension * i;for (int ii = 0; ii < dimension; ii++)fprintf(f2, "%.6f\t", relationVec[last + ii]);fprintf(f2,"\n");}for (int i = 0; i < entityTotal; i++) {int last = i * dimension;for (int ii = 0; ii < dimension; ii++)fprintf(f3, "%.6f\t", entityVec[last + ii] );fprintf(f3,"\n");}fclose(f2);fclose(f3); } /*Main function*/ int main() {time_t start = time(NULL);init();train_transe(NULL);out_transe();cout << time(NULL) - start << " s" << endl;return 0; }

總結

以上是生活随笔為你收集整理的TransE代码实践(很详细)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。