在windows下執行Felzenszwalb的Deformable Part Model(DPM)原始碼voc-release3.1來訓練自己的模型
我的環境
DPM原始碼版本:voc-release3.1
VOC開發包版本:VOC2007_devkit_08-Jun
使用的訓練資料集:VOC2007
包括:訓練驗證集:VOC2007_trainval_06-Nov(438MB)
測試集:VOC2007_test_06-Nov-2007(430MB)
Matlab版本:MatlabR2012b
c++編譯器:VS2010
系統:Win7 32位
為什麼不使用voc-release4.01呢?因為第4版中加入了目標檢測語法(Grammars),並且還使用了非對稱部件分部等等,雖然準確度提高了,但原始碼變得更加複雜,不利於原始碼分析。而相對來說第3版精簡了不少,更容易分析。
首先需要下載voc-release3.1和VOCdevkit開發包:
Deformable Part Model 第三版voc-release3.1下載:http://cs.brown.edu/~pff/latent-release3/
PASCAL VOC 2007 資料集及開發包下載:http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2007/index.html
注意不要只下載訓練驗證集VOC2007_trainval_06-Nov,還要下載測試集VOC2007_test_06-Nov-2007,然後把測試集中的xml標註檔案拷貝到VOCdevkit\VOC2007\Annotations資料夾內,把測試集中的jpeg圖片拷貝到VOCdevkit\VOC2007\JPEGImages資料夾內,這樣整個資料集才完整,否則在訓練或測試的時候可能出現找不到需要讀取的標註檔案或圖片的錯誤。
有關Deformable Part Model參見論文
A Discriminatively Trained, Multiscale,Deformable Part Model[CVPR 2008]的中文翻譯
Object Detection with Discriminatively Trained Part Based Models[PAMI 2010]的中文翻譯
及 有關可變形部件模型(Deformable Part Model)的一些說明
Pedro Felzenszwalb的個人主頁:http://cs.brown.edu/~pff/
1、修改globals.m中的一些全域性變數(主要是目錄設定)
cachedir= 'D:\DPMtrain\VOCCache\';
% 訓練好的模型結果和中間資料的檔案目錄,此目錄可以自己任意指定
tmpdir ='D:\DPMtrain\VOCtemp\';
% 訓練中用到的臨時檔案的目錄,臨時檔案可能會很大,此目錄可以自己任意指定
VOCdevkit =['H:\文件檔案\工作\█計算機視覺█\資料集\PascalVOC\VOC2007\VOCdevkit'];
% PASCAL VOC 開發包目錄,定位到VOC開發包所在目錄
2、修改VOCdevkit開發包中的VOCinit.m檔案,設定資料集目錄
我們使用VOC2007資料集,所以將VOC2006標識設為false(預設就是false)。
如果將解壓出來的VOC2007資料集的資料夾放在VOCdevkit目錄下的話,就不用再修改VOCinit.m中的目錄設定了,因為程式碼中預設就是這樣的目錄安排。但如果想把資料集放到其他地方,可以修改VOCopts.datadir目錄,指向資料集所在目錄。
我是直接將VOC2007資料夾放在了VOCdevkit下,目錄結構如下:
-VOCdevkit
-local
-VOC2006
-VOC2007
-results
-VOC2006
-VOC2007
-VOC2007
-Annotations
-ImageSets
-JPEGImages
-SegmentationClass
-SegmentationObject
-VOCcode
3、pascal_data.m 從PASCAL資料集中獲取指定類別目標的訓練資料
分析程式碼時,為了避免載入整個資料集,所以我在VOCdevkit\VOC2007\ImageSets\Main中新建了兩個圖片檔案列表:
trainval_smallset.txt和train_smallset.txt
每個裡面只有一兩百個檔名,分別拷貝自trainval.txt和train.txt。
對應的,在pascal_data.m中修改下程式碼,載入我新建的小檔案集:
載入正樣本列表改為:
ids= textread(sprintf(VOCopts.imgsetpath, 'trainval_smallset'), '%s');
負樣本列表對應修改。
這裡要注意下:VOCdevkit\VOC2007\ImageSets\Main中有幾個列表檔案容易混淆:
train.txt 是所有用來訓練的圖片檔案的檔名列表
trianval.txt是所有用來訓練和驗證的圖片檔案的檔名列表
val.txt是所有用來驗證的圖片檔案的檔名列表
上面三個集合對應所有目標類別的訓練和驗證。
還有幾個train_train.txt,train_trainval.txt,train.val.txt
這三個是“火車”類別的訓練、訓練+驗證、驗證圖片集,
所以要分清楚。
4、修改rewritedat.m檔案中的兩個系統呼叫命令
在matlab命令列中執行pascal(‘person’,1),即訓練含一個元件(component)模型的人體類別DPM模型,看看出什麼錯誤,一點一點來修改。
錯誤如下:
'mv' 不是內部或外部命令,也不是可執行的程式
Error in rewritedat (line 38)
所以來修改下rewritedat.m檔案
將第13行的 unix(['mv ' datfile ' ' oldfile]);
替換為:system(['move ' datfile ' ' oldfile]);
第44行的 unix(['cp ' inffile ' ' oldfile]);
替換為:system(['copy ' inffile ' ' oldfile]);
5、修改train.m檔案
修改完rewritedat.m檔案後,再次呼叫pascal(‘person’,1),這次的問題是:
executing: ./learn 0.0020 1.0000 D:\DPMtrain\VOCtemp\person.hdr D:\DPMtrain\VOCtemp\person.dat D:\DPMtrain\VOCtemp\person.mod D:\DPMtrain\VOCtemp\person.inf D:\DPMtrain\VOCtemp\person.lob
'.' 不是內部或外部命令,也不是可執行的程式或批處理檔案。
這又是一個linux下的系統呼叫,所以需要修改train.m,
將第123行的 cmd = sprintf('./learn %.4f %.4f %s %s %s %s %s', ...
C, J, hdrfile, datfile, modfile, inffile, lobfile);
命令字串中的./去掉,變成:
cmd = sprintf('learn %.4f %.4f %s %s %s %s %s', ...
C, J, hdrfile, datfile, modfile, inffile, lobfile);
將第128行的 status = unix(cmd);
替換為: status = system(cmd);
修改完這部分後,還是會提示'learn' 不是內部或外部命令,也不是可執行的程式 ,因為我們還沒有編譯learn.cc呢。
6、編譯learn.cc
首先將learn.cc改名為learn.cpp,在VS2010中新建一個空的控制檯工程,新增原檔案learn.cpp
嘗試編譯,錯誤提示為:Cannot open include file: 'sys/time.h': No such file or directoryc:\test\dpm_learn\dpm_learn\learn.cpp5
這是linux中的目錄格式,直接將第5行的#include <sys/time.h> 改為 #include <time.h>,再次編譯,然後就出現了一大堆錯誤,有以下幾點:
(1) windows中的time.h檔案中沒有結構體timeval的定義,也沒有gettimeofday函式,從網上找了一段程式碼新增到learn.cpp中。
(2) 上一步加入的程式碼需要新增標頭檔案windows.h,而包含進這個標頭檔案後,就包含了系統中定義的min和max函式,所以需要註釋掉learn.cpp中定義的min和max函式,否則出錯。
(3) windows中沒有drand48和srand48的定義,把網友部落格中自己寫的這兩個函式新增進去。
(4) windows中沒有INFINITY的定義,自己定義一個。
(5) main函式中的int buf[labelsize+2];出錯,原因是VS中的c++編譯器不允許用變數指定陣列長度,改為使用new動態分配:
int *buf = new int[labelsize+2]; ,同時,在同一作用域最後delete [] buf;
以上5點修改完後,就沒有錯誤了,當然還有些警告,不過不用管,編譯執行,生成learn.exe可執行檔案,拷貝到voc-release3.1目錄下,等待訓練時被matlab程式碼通過系統呼叫來執行。
修改完後的完整learn.cpp檔案為:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
//#include <sys/time.h>
#include <errno.h>
#include <time.h> //windows中用以替代sys/time.h
#include <windows.h>//windows中用以替代sys/time.h
/*
* Optimize LSVM objective function via gradient descent.
*
* We use an adaptive cache mechanism. After a negative example
* scores beyond the margin multiple times it is removed from the
* training set for a fixed number of iterations.
*/
// Data File Format
// EXAMPLE*
//
// EXAMPLE:
// long label ints
// blocks int
// dim int
// DATA{blocks}
//
// DATA:
// block label float
// block data floats
//
// Internal Binary Format
// len int (byte length of EXAMPLE)
// EXAMPLE <see above>
// unique flag byte
// number of iterations
#define ITER 5000000
// small cache parameters
#define INCACHE 3
#define WAIT 10
// error checking
#define check(e) \
(e ? (void)0 : (printf("%s:%u error: %s\n%s\n", __FILE__, __LINE__, #e, strerror(errno)), exit(1)))
// number of non-zero blocks in example ex
#define NUM_NONZERO(ex) (((int *)ex)[labelsize+1])
// float pointer to data segment of example ex
#define EX_DATA(ex) ((float *)(ex + sizeof(int)*(labelsize+3)))
// class label (+1 or -1) for the example
#define LABEL(ex) (((int *)ex)[1])
// block label (converted to 0-based index)
#define BLOCK_IDX(data) (((int)data[0])-1)
//windows中沒有INFINITY的定義,自己定義一個
#define INFINITY 0xFFFFFFFFF
int labelsize;
int dim;
//windows下沒有gettimeofday函式,從網上找的一個替代函式
int gettimeofday(struct timeval *tp, void *tzp)
{
time_t clock;
struct tm tm;
SYSTEMTIME wtm;
GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond;
tm. tm_isdst = -1;
clock = mktime(&tm);
tp->tv_sec = clock;
tp->tv_usec = wtm.wMilliseconds * 1000;
return (0);
}
//參照網上自己寫的drand48和srand48函式
#define MNWZ 0x100000000
#define ANWZ 0x5DEECE66D
#define CNWZ 0xB16
static unsigned long long seed = 1;
double drand48(void)
{
seed = (ANWZ * seed + CNWZ) & 0xFFFFFFFFFFFFLL;
unsigned int x = seed >> 16;
return ((double)x / (double)MNWZ);
}
//static unsigned long long seed = 1;
void srand48(unsigned int i)
{
seed = (((long long int)i) << 16) | rand();
}
// comparison function for sorting examples
int comp(const void *a, const void *b) {
// sort by extended label first, and whole example second...
int c = memcmp(*((char **)a) + sizeof(int),
*((char **)b) + sizeof(int),
labelsize*sizeof(int));
if (c)
return c;
// labels are the same
int alen = **((int **)a);
int blen = **((int **)b);
if (alen == blen)
return memcmp(*((char **)a) + sizeof(int),
*((char **)b) + sizeof(int),
alen);
return ((alen < blen) ? -1 : 1);
}
// a collapsed example is a sequence of examples
struct collapsed {
char **seq;
int num;
};
// set of collapsed examples
struct data {
collapsed *x;
int num;
int numblocks;
int *blocksizes;
float *regmult;
float *learnmult;
};
// seed the random number generator with the current time
void seed_time() {
struct timeval tp;
check(gettimeofday(&tp, NULL) == 0);
srand48((long)tp.tv_usec);
}
//包含include.h後,系統中有min和max函式的定義,所以註釋掉下面的定義,否則出錯
//static inline double min(double x, double y) { return (x <= y ? x : y); }
//static inline double max(double x, double y) { return (x <= y ? y : x); }
// gradient descent
void gd(double C, double J, data X, double **w, double **lb) {
int num = X.num;
// state for random permutations
int *perm = (int *)malloc(sizeof(int)*X.num);
check(perm != NULL);
// state for small cache
int *W = (int *)malloc(sizeof(int)*num);
check(W != NULL);
for (int j = 0; j < num; j++)
W[j] = 0;
int t = 0;
while (t < ITER) {
// pick random permutation
for (int i = 0; i < num; i++)
perm[i] = i;
for (int swapi = 0; swapi < num; swapi++) {
int swapj = (int)(drand48()*(num-swapi)) + swapi;
int tmp = perm[swapi];
perm[swapi] = perm[swapj];
perm[swapj] = tmp;
}
// count number of examples in the small cache
int cnum = 0;
for (int i = 0; i < num; i++) {
if (W[i] <= INCACHE)
cnum++;
}
for (int swapi = 0; swapi < num; swapi++) {
// select example
int i = perm[swapi];
collapsed x = X.x[i];
// skip if example is not in small cache
if (W[i] > INCACHE) {
W[i]--;
continue;
}
// learning rate
double T = t + 1000.0;
double rateX = cnum * C / T;
double rateR = 1.0 / T;
if (t % 10000 == 0) {
printf(".");
fflush(stdout);
}
t++;
// compute max over latent placements
int M = -1;
double V = 0;
for (int m = 0; m < x.num; m++) {
double val = 0;
char *ptr = x.seq[m];
float *data = EX_DATA(ptr);
int blocks = NUM_NONZERO(ptr);
for (int j = 0; j < blocks; j++) {
int b = BLOCK_IDX(data);
data++;
for (int k = 0; k < X.blocksizes[b]; k++)
val += w[b][k] * data[k];
data += X.blocksizes[b];
}
if (M < 0 || val > V) {
M = m;
V = val;
}
}
// update model
for (int j = 0; j < X.numblocks; j++) {
double mult = rateR * X.regmult[j] * X.learnmult[j];
for (int k = 0; k < X.blocksizes[j]; k++) {
w[j][k] -= mult * w[j][k];
}
}
char *ptr = x.seq[M];
int label = LABEL(ptr);
if (label * V < 1.0) {
W[i] = 0;
float *data = EX_DATA(ptr);
int blocks = NUM_NONZERO(ptr);
for (int j = 0; j < blocks; j++) {
int b = BLOCK_IDX(data);
double mult = (label > 0 ? J : -1) * rateX * X.learnmult[b];
data++;
for (int k = 0; k < X.blocksizes[b]; k++)
w[b][k] += mult * data[k];
data += X.blocksizes[b];
}
} else if (label == -1) {
if (W[i] == INCACHE)
W[i] = WAIT;
else
W[i]++;
}
}
// apply lowerbounds
for (int j = 0; j < X.numblocks; j++) {
for (int k = 0; k < X.blocksizes[j]; k++) {
w[j][k] = max(w[j][k], lb[j][k]);
}
}
}
free(perm);
free(W);
}
// score examples
double *score(data X, char **examples, int num, double **w) {
double *s = (double *)malloc(sizeof(double)*num);
check(s != NULL);
for (int i = 0; i < num; i++) {
s[i] = 0.0;
float *data = EX_DATA(examples[i]);
int blocks = NUM_NONZERO(examples[i]);
for (int j = 0; j < blocks; j++) {
int b = BLOCK_IDX(data);
data++;
for (int k = 0; k < X.blocksizes[b]; k++)
s[i] += w[b][k] * data[k];
data += X.blocksizes[b];
}
}
return s;
}
// merge examples with identical labels
void collapse(data *X, char **examples, int num) {
collapsed *x = (collapsed *)malloc(sizeof(collapsed)*num);
check(x != NULL);
int i = 0;
x[0].seq = examples;
x[0].num = 1;
for (int j = 1; j < num; j++) {
if (!memcmp(x[i].seq[0]+sizeof(int), examples[j]+sizeof(int),
labelsize*sizeof(int))) {
x[i].num++;
} else {
i++;
x[i].seq = &(examples[j]);
x[i].num = 1;
}
}
X->x = x;
X->num = i+1;
}
int main(int argc, char **argv) {
seed_time();
int count;
data X;
// command line arguments
check(argc == 8);
double C = atof(argv[1]);
double J = atof(argv[2]);
char *hdrfile = argv[3];
char *datfile = argv[4];
char *modfile = argv[5];
char *inffile = argv[6];
char *lobfile = argv[7];
// read header file
FILE *f = fopen(hdrfile, "rb");
check(f != NULL);
int header[3];
count = fread(header, sizeof(int), 3, f);
check(count == 3);
int num = header[0];
labelsize = header[1];
X.numblocks = header[2];
X.blocksizes = (int *)malloc(X.numblocks*sizeof(int));
count = fread(X.blocksizes, sizeof(int), X.numblocks, f);
check(count == X.numblocks);
X.regmult = (float *)malloc(sizeof(float)*X.numblocks);
check(X.regmult != NULL);
count = fread(X.regmult, sizeof(float), X.numblocks, f);
check(count == X.numblocks);
X.learnmult = (float *)malloc(sizeof(float)*X.numblocks);
check(X.learnmult != NULL);
count = fread(X.learnmult, sizeof(float), X.numblocks, f);
check(count == X.numblocks);
check(num != 0);
fclose(f);
printf("%d examples with label size %d and %d blocks\n",
num, labelsize, X.numblocks);
printf("block size, regularization multiplier, learning rate multiplier\n");
dim = 0;
for (int i = 0; i < X.numblocks; i++) {
dim += X.blocksizes[i];
printf("%d, %.2f, %.2f\n", X.blocksizes[i], X.regmult[i], X.learnmult[i]);
}
// read examples
f = fopen(datfile, "rb");
check(f != NULL);
printf("Reading examples\n");
char **examples = (char **)malloc(num*sizeof(char *));
check(examples != NULL);
for (int i = 0; i < num; i++) {
// we use an extra byte in the end of each example to mark unique
// we use an extra int at the start of each example to store the
// example's byte length (excluding unique flag and this int)
//int buf[labelsize+2]; //windows下不支援這樣分配,換成new動態分配
int *buf = new int[labelsize+2]; //動態分配
count = fread(buf, sizeof(int), labelsize+2, f);
check(count == labelsize+2);
// byte length of an example's data segment
int len = sizeof(int)*(labelsize+2) + sizeof(float)*buf[labelsize+1];
// memory for data, an initial integer, and a final byte
examples[i] = (char *)malloc(sizeof(int)+len+1);
check(examples[i] != NULL);
// set data segment's byte length
((int *)examples[i])[0] = len;
// set the unique flag to zero
examples[i][sizeof(int)+len] = 0;
// copy label data into example
for (int j = 0; j < labelsize+2; j++)
((int *)examples[i])[j+1] = buf[j];
// read the rest of the data segment into the example
count = fread(examples[i]+sizeof(int)*(labelsize+3), 1,
len-sizeof(int)*(labelsize+2), f);
check(count == len-sizeof(int)*(labelsize+2));
delete [] buf; //刪除buf
}
fclose(f);
printf("done\n");
// sort
printf("Sorting examples\n");
char **sorted = (char **)malloc(num*sizeof(char *));
check(sorted != NULL);
memcpy(sorted, examples, num*sizeof(char *));
qsort(sorted, num, sizeof(char *), comp);
printf("done\n");
// find unique examples
int i = 0;
int len = *((int *)sorted[0]);
sorted[0][sizeof(int)+len] = 1;
for (int j = 1; j < num; j++) {
int alen = *((int *)sorted[i]);
int blen = *((int *)sorted[j]);
if (alen != blen ||
memcmp(sorted[i] + sizeof(int), sorted[j] + sizeof(int), alen)) {
i++;
sorted[i] = sorted[j];
sorted[i][sizeof(int)+blen] = 1;
}
}
int num_unique = i+1;
printf("%d unique examples\n", num_unique);
// collapse examples
collapse(&X, sorted, num_unique);
printf("%d collapsed examples\n", X.num);
// initial model
double **w = (double **)malloc(sizeof(double *)*X.numblocks);
check(w != NULL);
f = fopen(modfile, "rb");
for (int i = 0; i < X.numblocks; i++) {
w[i] = (double *)malloc(sizeof(double)*X.blocksizes[i]);
check(w[i] != NULL);
count = fread(w[i], sizeof(double), X.blocksizes[i], f);
check(count == X.blocksizes[i]);
}
fclose(f);
// lower bounds
double **lb = (double **)malloc(sizeof(double *)*X.numblocks);
check(lb != NULL);
f = fopen(lobfile, "rb");
for (int i = 0; i < X.numblocks; i++) {
lb[i] = (double *)malloc(sizeof(double)*X.blocksizes[i]);
check(lb[i] != NULL);
count = fread(lb[i], sizeof(double), X.blocksizes[i], f);
check(count == X.blocksizes[i]);
}
fclose(f);
// train
printf("Training");
gd(C, J, X, w, lb);
printf("done\n");
// save model
printf("Saving model\n");
f = fopen(modfile, "wb");
check(f != NULL);
for (int i = 0; i < X.numblocks; i++) {
count = fwrite(w[i], sizeof(double), X.blocksizes[i], f);
check(count == X.blocksizes[i]);
}
fclose(f);
// score examples
printf("Scoring\n");
double *s = score(X, examples, num, w);
// Write info file
printf("Writing info file\n");
f = fopen(inffile, "w");
check(f != NULL);
for (int i = 0; i < num; i++) {
int len = ((int *)examples[i])[0];
// label, score, unique flag
count = fprintf(f, "%d\t%f\t%d\n", ((int *)examples[i])[1], s[i],
(int)examples[i][sizeof(int)+len]);
check(count > 0);
}
fclose(f);
printf("Freeing memory\n");
for (int i = 0; i < X.numblocks; i++) {
free(w[i]);
free(lb[i]);
}
free(w);
free(lb);
free(s);
for (int i = 0; i < num; i++)
free(examples[i]);
free(examples);
free(sorted);
free(X.x);
free(X.blocksizes);
free(X.regmult);
free(X.learnmult);
return 0;
}
7 陣列下標越界錯誤
陣列越界錯誤有好幾處,我注意到的有:
(1)pascal_train.m中
合併模型並進行LSVM訓練部分
即註釋 %merge models and train using latent detections & hard negatives下的
model = train(cls, model, pos, neg(1:200), 0, 0, 2, 2, 2^28, true, 0.7);
原因是這裡我的負樣本集neg中的負樣本數目沒有達到200個,所以這裡改為:
model = train(cls, model, pos, neg(1:min(length(neg),200)), 0, 0, 2, 2, 2^28, true, 0.7);
還有新增部件更新模型部分
即註釋% add parts and update models using latent detections & hard negatives.下的兩處呼叫train函式的地方,
都將neg(1:200)改為neg(1:min(length(neg),200))
(2)網友pozen提出的rewritedat.m中可能出現的下標越界情況,
將28行左右的dim = info(end);改為:
if length(info) == 0
dim = 0;
else
dim = info(end);
end
將38行左右的dim = y(end);改為:
if length(y) == 0
dim = 0;
else
dim = y(end);
end
參考:
http://blog.csdn.net/pozen/article/details/7103412
http://blog.csdn.net/dreamd1987/article/details/7399151
自己用少量資料訓練了一個單元件人體模型,擷取trainval.txt中的前50個圖片檔名做正樣本,train.txt中的前300個做負樣本,經過pascal.data函式處理後,獲得了含176個負樣本的neg陣列,含45個正樣本的pos陣列。learn.cc中的迭代次數我沒改,還是每次train迭代500萬次(感覺時間都花在這裡了,如果只是做測試的話,可以修改learn.cc中的迭代次數ITER值),訓練過程用了大概1小時左右吧,訓練完後用PASCAL開發包中的評價函式做了評價,正確率和召回率都是0,平均精度AP也是0,在預料之中。
訓練完後,最終結果在cachedir目錄中,很多中間資料也在這個目錄中,如下:
其中person_final.mat就是訓練好的最終模型。原始碼中訓練的每個階段都會將中間資料儲存下來,所以即使某一階段出現了錯誤,下次重新執行時自動載入上次儲存的資料,而不用再次計算,非常方便。
訓練出來的模型的視覺化如下:
參考
在windows下執行Felzenszwalb的Deformable Part Model(DPM)原始碼voc-release3.1來訓練自己的模型
相關文章
- 在Windows下執行Felzenszwalb的star-cascade DPM(Deformable Part Models)目標檢測Matlab原始碼WindowsORMMatlab原始碼
- 用DPM(Deformable Part Model,voc-release3.1)演算法在INRIA資料集上訓練自己的人體檢測模型ORM演算法模型
- 在Windows下執行Felzenszwalb的Deformable Part Models(voc-release4.01)目標檢測matlab原始碼WindowsORMMatlab原始碼
- 關於DPM(Deformable Part Model)演算法中模型結構的解釋ORM演算法模型
- 關於DPM(Deformable Part Model)演算法中模型視覺化的解釋ORM演算法模型視覺化
- 判別訓練的多尺度可變形部件模型 A Discriminatively Trained, Multiscale, Deformable Part Model模型AIORM
- 有關可變形部件模型(Deformable Part Model)的一些說明模型ORM
- [原始碼解析] 模型並行分散式訓練 Megatron (3) ---模型並行實現原始碼模型並行分散式
- 使用判別訓練的部件模型進行目標檢測 Object Detection with Discriminatively Trained Part Based Models模型ObjectAI
- [原始碼解析] 模型並行分散式訓練Megatron (5) --Pipedream Flush原始碼模型並行分散式
- [原始碼分析] Facebook如何訓練超大模型 --- (3)原始碼大模型
- [原始碼分析] Facebook如何訓練超大模型---(4)原始碼大模型
- [原始碼分析] Facebook如何訓練超大模型--- (5)原始碼大模型
- [原始碼分析] Facebook如何訓練超大模型---(1)原始碼大模型
- [原始碼分析] Facebook如何訓練超大模型 --- (2)原始碼大模型
- java在windows下執行JavaWindows
- fasttext訓練模型程式碼AST模型
- 【JSConf EU 2018】用 JavaScript 來在客戶端上訓練和執行機器學習模型JSJavaScript客戶端機器學習模型
- [原始碼解析] 模型並行分散式訓練Megatron (2) --- 整體架構原始碼模型並行分散式架構
- [原始碼解析] 模型並行分散式訓練Megatron (1) --- 論文 & 基礎原始碼模型並行分散式
- DFSMN在阿里巴巴的應用以及如何採用開原始碼訓練DFSMN模型阿里原始碼模型
- pytorch-模型儲存與載入自己訓練的模型詳解PyTorch模型
- [原始碼解析] 模型並行分散式訓練 Megatron (4) --- 如何設定各種並行原始碼模型並行分散式
- 執行緒池執行模型原始碼全解析執行緒模型原始碼
- 使用Bert預訓練模型文字分類(內附原始碼)模型文字分類原始碼
- linux下QT在windows下執行LinuxQTWindows
- 自訓練 + 預訓練 = 更好的自然語言理解模型模型
- ctf訓練 命令執行漏洞
- 在 Windows 系統上執行 VIC 水文模型Windows模型
- windows下實現自己的第一個python指令碼檔案並.exe執行WindowsPython指令碼
- 個人程式設計助手: 訓練你自己的編碼助手程式設計
- 可以在Windows的"執行"中直接執行的程式Windows
- 用Flask在伺服器上部署訓練好的模型Flask伺服器模型
- PyTorch 模型訓練實⽤教程(程式碼訓練步驟講解)PyTorch模型
- 用Windows電腦訓練深度學習模型?超詳細配置教程來了Windows深度學習模型
- 【預訓練語言模型】 使用Transformers庫進行BERT預訓練模型ORM
- Windows10 使用 Tensorflow Object_detection API 訓練自己的資料WindowsObjectAPI
- BERT預訓練模型的演進過程!(附程式碼)模型