diff --git a/.gitignore b/.gitignore index bea19ff4..9cab30c1 100644 --- a/.gitignore +++ b/.gitignore @@ -16,8 +16,9 @@ convnet/ decaf/ submission/ cfg/ -darknet +#darknet .fuse* +*.user* # OS Generated # .DS_Store* diff --git a/ThirdParty/CUDA.pri b/ThirdParty/CUDA.pri new file mode 100644 index 00000000..21b47303 --- /dev/null +++ b/ThirdParty/CUDA.pri @@ -0,0 +1,25 @@ +# CUDA Lib + +CUDA_ROOT = $$(CUDA_ROOT) +isEmpty(CUDA_ROOT) { + CUDA_ROOT = $$LIBS_ROOT/CUDA +} + +INCLUDEPATH += $$CUDA_ROOT/include + +LIBS += -L$$CUDA_ROOT/bin +LIBS += -L$$CUDA_ROOT/nvvm/bin +LIBS += -L$$CUDA_ROOT/lib/x64 \ + -lcuda \ + -lcudart \ + -lcublas \ + -lcurand + +# install +install_dependency_cuda.path = $$INSTALL_PREFIX/bin +install_dependency_cuda.files = \ + $$CUDA_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*cudart*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* \ + $$CUDA_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*cublas*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* \ + $$CUDA_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*curand*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* \ + $$CUDA_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*cudnn*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* +INSTALLS += install_dependency_cuda diff --git a/ThirdParty/OpenCV.pri b/ThirdParty/OpenCV.pri new file mode 100644 index 00000000..16350a59 --- /dev/null +++ b/ThirdParty/OpenCV.pri @@ -0,0 +1,39 @@ +# OpenCV Lib + +OPENCV_ROOT = $$(OPENCV_ROOT) +isEmpty(OPENCV_ROOT) { + OPENCV_ROOT = $$LIBS_ROOT/OpenCV +} + +include($$OPENCV_ROOT/info.pri) # define "CV_MAJOR_VERSION" and "CV_LIB_POSTFIX" + +INCLUDEPATH += $$OPENCV_ROOT/include + +win32 { + CONFIG(debug, debug|release): OPENCV_LIB_POSTFIX = $$CV_LIB_POSTFIX"d" + else: OPENCV_LIB_POSTFIX = $$CV_LIB_POSTFIX +} else { +} + +LIBS += -L$$OPENCV_ROOT/bin +LIBS += -L$$OPENCV_ROOT/lib \ + -lopencv_core$$OPENCV_LIB_POSTFIX \ + -lopencv_highgui$$OPENCV_LIB_POSTFIX \ + -lopencv_imgproc$$OPENCV_LIB_POSTFIX + +greaterThan(CV_MAJOR_VERSION, 2) { + LIBS += \ + -lopencv_imgcodecs$$OPENCV_LIB_POSTFIX \ + -lopencv_videoio$$OPENCV_LIB_POSTFIX + !win32: CONFIG(debug, debug|release): QMAKE_CFLAGS += -O4 -g +} + +# install +install_dependency_opencv.path = $$INSTALL_PREFIX/bin +install_dependency_opencv.files = \ + $$OPENCV_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*opencv_core*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* \ + $$OPENCV_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*opencv_highgui*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* \ + $$OPENCV_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*opencv_imgproc*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* \ + $$OPENCV_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*opencv_imgcodecs*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* \ + $$OPENCV_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*opencv_videoio*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* +INSTALLS += install_dependency_opencv diff --git a/ThirdParty/Pthreads.pri b/ThirdParty/Pthreads.pri new file mode 100644 index 00000000..7d944b33 --- /dev/null +++ b/ThirdParty/Pthreads.pri @@ -0,0 +1,17 @@ +# Pthreads Lib + +PTHREADS_ROOT = $$(PTHREADS_ROOT) +isEmpty(PTHREADS_ROOT) { + PTHREADS_ROOT = $$LIBS_ROOT/Pthreads +} + +INCLUDEPATH += $$PTHREADS_ROOT/include + +LIBS += -L$$PTHREADS_ROOT/bin +LIBS += -L$$PTHREADS_ROOT/lib \ + -lpthreadVC2 + +# install +install_dependency_pthreads.path = $$INSTALL_PREFIX/bin +install_dependency_pthreads.files = $$PTHREADS_ROOT/$$INSTALL_DEPEND_LIB_DIR_NAME/*pthread*$$INSTALL_DEPEND_LIB_FILE_SUFFIX* +INSTALLS += install_dependency_pthreads diff --git a/darknet.pro b/darknet.pro new file mode 100644 index 00000000..74f664cb --- /dev/null +++ b/darknet.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + darknet diff --git a/darknet/darknet.pro b/darknet/darknet.pro new file mode 100644 index 00000000..47c1a840 --- /dev/null +++ b/darknet/darknet.pro @@ -0,0 +1,84 @@ +VERSION = 0.1.0 +TEMPLATE = app +include($$PWD/../general.pri) + +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +DEFINES += GPU +DEFINES += CUDNN +DEFINES += OPENCV +DEFINES += OPENMP + +INCLUDEPATH += \ + $$PWD/../include \ + $$PWD/../src + +HEADERS += \ + $$files($$PWD/../src/*.h) + +SOURCES += \ + $$files($$PWD/../src/*.c) \ + $$files($$PWD/../examples/*.c) + +win32 { + INCLUDEPATH += $$PWD/../windows + HEADERS += $$files($$PWD/../windows/*.h) + SOURCES += $$files($$PWD/../windows/*.c) +} + + +win32 { + DEFINES += HAVE_STRUCT_TIMESPEC + include($$PWD/../ThirdParty/Pthreads.pri) +} else { + LIBS += -lpthread +} +contains(DEFINES, GPU): include($$PWD/../ThirdParty/CUDA.pri) +contains(DEFINES, GPU): contains(DEFINES, CUDNN): LIBS += -lcudnn +contains(DEFINES, OPENCV): include($$PWD/../ThirdParty/OpenCV.pri) +contains(DEFINES, OPENMP) { + win32 { + QMAKE_CFLAGS += /openmp + } else { + QMAKE_CFLAGS += -fopenmp + LIBS += -fopenmp + } +} +win32: LIBS += -lWs2_32 + + +contains(DEFINES, GPU) { + CUDA_SOURCES += $$files($$PWD/../src/*.cu) + NVCC_OPTIONS += \ + -gencode arch=compute_30,code=sm_30 \ + -gencode arch=compute_35,code=sm_35 \ + -gencode arch=compute_50,code=[sm_50,compute_50] \ + -gencode arch=compute_52,code=[sm_52,compute_52] \ + $$join(DEFINES, " -D", "-D", "") \ + $$join(INCLUDEPATH, "\" -I\"", "-I\"", "\"") \ + $$LIBS + + CONFIG(debug, debug|release): NVCC_OPTIONS += -D_DEBUG + + win32 { + CONFIG(debug, debug|release): NVCC_OPTIONS += -Xcompiler /MDd + else: NVCC_OPTIONS += -Xcompiler /MD + } + + cuda_compiler.input = CUDA_SOURCES + cuda_compiler.output = $$DEST_ROOT/darknet/$$CONFIGURATION_NAME/${QMAKE_FILE_BASE}_cuda$$BUILD_OBJECT_FILE_SUFFIX + cuda_compiler.commands = nvcc $$NVCC_OPTIONS -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} + cuda_compiler.dependency_type = TYPE_C + QMAKE_EXTRA_COMPILERS += cuda_compiler +} + + +# install +target.path = $$INSTALL_PREFIX/bin +install_data.path = $$INSTALL_PREFIX/bin +install_data.files = $$PWD/../data +install_cfg.path = $$INSTALL_PREFIX/bin +install_cfg.files = $$PWD/../cfg +INSTALLS += target install_data install_cfg diff --git a/examples/art.c b/examples/art.c index 7d58c5d9..404f249d 100644 --- a/examples/art.c +++ b/examples/art.c @@ -1,6 +1,10 @@ #include "darknet.h" +#ifdef WIN32 +#include +#else #include +#endif void demo_art(char *cfgfile, char *weightfile, int cam_index) { diff --git a/examples/attention.c b/examples/attention.c index cd1e579d..221b68f9 100644 --- a/examples/attention.c +++ b/examples/attention.c @@ -1,6 +1,10 @@ #include "darknet.h" +#ifdef WIN32 +#include +#else #include +#endif #include void extend_data_truth(data *d, int n, float val) diff --git a/examples/classifier.c b/examples/classifier.c index d118ea58..9b65bbae 100644 --- a/examples/classifier.c +++ b/examples/classifier.c @@ -1,6 +1,15 @@ #include "darknet.h" - +#ifdef WIN32 +#include +#endif +#ifdef WIN32 +#include +#else #include +#endif +#ifdef WIN32 +#include +#endif #include float *get_regression_values(char **labels, int n) diff --git a/examples/dice.c b/examples/dice.c index f56d76c0..15ded456 100644 --- a/examples/dice.c +++ b/examples/dice.c @@ -9,13 +9,13 @@ void train_dice(char *cfgfile, char *weightfile) char *base = basecfg(cfgfile); char *backup_directory = "/home/pjreddie/backup/"; printf("%s\n", base); - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net.learning_rate, net.momentum, net.decay); + printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net->learning_rate, net->momentum, net->decay); int imgs = 1024; - int i = *net.seen/imgs; + int i = *net->seen/imgs; char **labels = dice_labels; list *plist = get_paths("data/dice/dice.train.list"); char **paths = (char **)list_to_array(plist); @@ -24,16 +24,16 @@ void train_dice(char *cfgfile, char *weightfile) while(1){ ++i; time=clock(); - data train = load_data_old(paths, imgs, plist->size, labels, 6, net.w, net.h); + data train = load_data_old(paths, imgs, plist->size, labels, 6, net->w, net->h); printf("Loaded: %lf seconds\n", sec(clock()-time)); time=clock(); float loss = train_network(net, train); if(avg_loss == -1) avg_loss = loss; avg_loss = avg_loss*.9 + loss*.1; - printf("%d: %f, %f avg, %lf seconds, %ld images\n", i, loss, avg_loss, sec(clock()-time), *net.seen); + printf("%d: %f, %f avg, %lf seconds, %ld images\n", i, loss, avg_loss, sec(clock()-time), *net->seen); free_data(train); - if((i % 100) == 0) net.learning_rate *= .1; + if((i % 100) == 0) net->learning_rate *= .1; if(i%100==0){ char buff[256]; sprintf(buff, "%s/%s_%d.weights",backup_directory,base, i); @@ -44,9 +44,9 @@ void train_dice(char *cfgfile, char *weightfile) void validate_dice(char *filename, char *weightfile) { - network net = parse_network_cfg(filename); + network *net = parse_network_cfg(filename); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } srand(time(0)); @@ -57,7 +57,7 @@ void validate_dice(char *filename, char *weightfile) int m = plist->size; free_list(plist); - data val = load_data_old(paths, m, 0, labels, 6, net.w, net.h); + data val = load_data_old(paths, m, 0, labels, 6, net->w, net->h); float *acc = network_accuracies(net, val, 2); printf("Validation Accuracy: %f, %d images\n", acc[0], m); free_data(val); @@ -65,11 +65,11 @@ void validate_dice(char *filename, char *weightfile) void test_dice(char *cfgfile, char *weightfile, char *filename) { - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - set_batch_network(&net, 1); + set_batch_network(net, 1); srand(2222222); int i = 0; char **names = dice_labels; @@ -86,7 +86,7 @@ void test_dice(char *cfgfile, char *weightfile, char *filename) if(!input) return; strtok(input, "\n"); } - image im = load_image_color(input, net.w, net.h); + image im = load_image_color(input, net->w, net->h); float *X = im.data; float *predictions = network_predict(net, X); top_predictions(net, 6, indexes); diff --git a/examples/go.c b/examples/go.c index 688579dc..ec0b0df2 100644 --- a/examples/go.c +++ b/examples/go.c @@ -2,11 +2,25 @@ #include #include +#ifdef WIN32 +#include +#else #include +#endif + +#ifdef WIN32 +#define STDIN_FILENO 0 +#endif + +#ifdef WIN32 +#define popen _popen +#define pclose _pclose +#define sleep Sleep +#endif int inverted = 1; int noi = 1; -static const int nind = 10; +#define nind 10 int legal_go(float *b, float *ko, int p, int r, int c); int check_ko(float *x, float *ko); diff --git a/examples/regressor.c b/examples/regressor.c index 60a9f2b9..cd81b1fd 100644 --- a/examples/regressor.c +++ b/examples/regressor.c @@ -1,5 +1,15 @@ #include "darknet.h" +#ifdef WIN32 +#include +#endif +#ifdef WIN32 +#include +#else #include +#endif +#ifdef WIN32 +#include +#endif #include void train_regressor(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear) diff --git a/examples/rnn_vid.c b/examples/rnn_vid.c index e8879235..9bab7394 100644 --- a/examples/rnn_vid.c +++ b/examples/rnn_vid.c @@ -4,7 +4,7 @@ image get_image_from_stream(CvCapture *cap); image ipl_to_image(IplImage* src); -void reconstruct_picture(network net, float *features, image recon, image update, float rate, float momentum, float lambda, int smooth_size, int iters); +void reconstruct_picture(network *net, float *features, image recon, image update, float rate, float momentum, float lambda, int smooth_size, int iters); typedef struct { @@ -12,17 +12,17 @@ typedef struct { float *y; } float_pair; -float_pair get_rnn_vid_data(network net, char **files, int n, int batch, int steps) +float_pair get_rnn_vid_data(network *net, char **files, int n, int batch, int steps) { int b; - assert(net.batch == steps + 1); + assert(net->batch == steps + 1); image out_im = get_network_image(net); int output_size = out_im.w*out_im.h*out_im.c; printf("%d %d %d\n", out_im.w, out_im.h, out_im.c); - float *feats = calloc(net.batch*batch*output_size, sizeof(float)); + float *feats = calloc(net->batch*batch*output_size, sizeof(float)); for(b = 0; b < batch; ++b){ - int input_size = net.w*net.h*net.c; - float *input = calloc(input_size*net.batch, sizeof(float)); + int input_size = net->w*net->h*net->c; + float *input = calloc(input_size*net->batch, sizeof(float)); char *filename = files[rand()%n]; CvCapture *cap = cvCaptureFromFile(filename); int frames = cvGetCaptureProperty(cap, CV_CAP_PROP_FRAME_COUNT); @@ -37,11 +37,11 @@ float_pair get_rnn_vid_data(network net, char **files, int n, int batch, int ste cvSetCaptureProperty(cap, CV_CAP_PROP_POS_FRAMES, index); int i; - for(i = 0; i < net.batch; ++i){ + for(i = 0; i < net->batch; ++i){ IplImage* src = cvQueryFrame(cap); image im = ipl_to_image(src); rgbgr_image(im); - image re = resize_image(im, net.w, net.h); + image re = resize_image(im, net->w, net->h); //show_image(re, "loaded"); //cvWaitKey(10); memcpy(input + i*input_size, re.data, input_size*sizeof(float)); @@ -52,7 +52,7 @@ float_pair get_rnn_vid_data(network net, char **files, int n, int batch, int ste free(input); - for(i = 0; i < net.batch; ++i){ + for(i = 0; i < net->batch; ++i){ memcpy(feats + (b + i*batch)*output_size, output + i*output_size, output_size*sizeof(float)); } @@ -76,32 +76,32 @@ void train_vid_rnn(char *cfgfile, char *weightfile) char *base = basecfg(cfgfile); printf("%s\n", base); float avg_loss = -1; - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net.learning_rate, net.momentum, net.decay); - int imgs = net.batch*net.subdivisions; - int i = *net.seen/imgs; + printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net->learning_rate, net->momentum, net->decay); + int imgs = net->batch*net->subdivisions; + int i = *net->seen/imgs; list *plist = get_paths(train_videos); int N = plist->size; char **paths = (char **)list_to_array(plist); clock_t time; - int steps = net.time_steps; - int batch = net.batch / net.time_steps; + int steps = net->time_steps; + int batch = net->batch / net->time_steps; - network extractor = parse_network_cfg("cfg/extractor.cfg"); - load_weights(&extractor, "/home/pjreddie/trained/yolo-coco.conv"); + network *extractor = parse_network_cfg("cfg/extractor.cfg"); + load_weights(extractor, "/home/pjreddie/trained/yolo-coco.conv"); - while(get_current_batch(net) < net.max_batches){ + while(get_current_batch(net) < net->max_batches){ i += 1; time=clock(); float_pair p = get_rnn_vid_data(extractor, paths, N, batch, steps); - copy_cpu(net.inputs*net.batch, p.x, 1, net.input, 1); - copy_cpu(net.truths*net.batch, p.y, 1, net.truth, 1); - float loss = train_network_datum(net) / (net.batch); + copy_cpu(net->inputs*net->batch, p.x, 1, net->input, 1); + copy_cpu(net->truths*net->batch, p.y, 1, net->truth, 1); + float loss = train_network_datum(net) / (net->batch); free(p.x); @@ -126,16 +126,16 @@ void train_vid_rnn(char *cfgfile, char *weightfile) } -image save_reconstruction(network net, image *init, float *feat, char *name, int i) +image save_reconstruction(network *net, image *init, float *feat, char *name, int i) { image recon; if (init) { recon = copy_image(*init); } else { - recon = make_random_image(net.w, net.h, 3); + recon = make_random_image(net->w, net->h, 3); } - image update = make_image(net.w, net.h, 3); + image update = make_image(net->w, net->h, 3); reconstruct_picture(net, feat, recon, update, .01, .9, .1, 2, 50); char buff[256]; sprintf(buff, "%s%d", name, i); @@ -146,15 +146,15 @@ image save_reconstruction(network net, image *init, float *feat, char *name, int void generate_vid_rnn(char *cfgfile, char *weightfile) { - network extractor = parse_network_cfg("cfg/extractor.recon.cfg"); - load_weights(&extractor, "/home/pjreddie/trained/yolo-coco.conv"); + network *extractor = parse_network_cfg("cfg/extractor.recon.cfg"); + load_weights(extractor, "/home/pjreddie/trained/yolo-coco.conv"); - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - set_batch_network(&extractor, 1); - set_batch_network(&net, 1); + set_batch_network(extractor, 1); + set_batch_network(net, 1); int i; CvCapture *cap = cvCaptureFromFile("/extra/vid/ILSVRC2015/Data/VID/snippets/val/ILSVRC2015_val_00007030.mp4"); @@ -163,7 +163,7 @@ void generate_vid_rnn(char *cfgfile, char *weightfile) image last; for(i = 0; i < 25; ++i){ image im = get_image_from_stream(cap); - image re = resize_image(im, extractor.w, extractor.h); + image re = resize_image(im, extractor->w, extractor->h); feat = network_predict(extractor, re.data); if(i > 0){ printf("%f %f\n", mean_array(feat, 14*14*512), variance_array(feat, 14*14*512)); diff --git a/examples/segmenter.c b/examples/segmenter.c index d73aceb3..5b01a5ac 100644 --- a/examples/segmenter.c +++ b/examples/segmenter.c @@ -1,5 +1,15 @@ #include "darknet.h" +#ifdef WIN32 +#include +#endif +#ifdef WIN32 +#include +#else #include +#endif +#ifdef WIN32 +#include +#endif #include void train_segmenter(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear, int display) diff --git a/examples/swag.c b/examples/swag.c index c22d7855..9c221e79 100644 --- a/examples/swag.c +++ b/examples/swag.c @@ -1,5 +1,9 @@ #include "darknet.h" +#ifdef WIN32 +#include +#else #include +#endif void train_swag(char *cfgfile, char *weightfile) { @@ -9,16 +13,16 @@ void train_swag(char *cfgfile, char *weightfile) char *base = basecfg(cfgfile); printf("%s\n", base); float avg_loss = -1; - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net.learning_rate, net.momentum, net.decay); - int imgs = net.batch*net.subdivisions; - int i = *net.seen/imgs; + printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net->learning_rate, net->momentum, net->decay); + int imgs = net->batch*net->subdivisions; + int i = *net->seen/imgs; data train, buffer; - layer l = net.layers[net.n - 1]; + layer l = net->layers[net->n - 1]; int side = l.side; int classes = l.classes; @@ -29,8 +33,8 @@ void train_swag(char *cfgfile, char *weightfile) char **paths = (char **)list_to_array(plist); load_args args = {0}; - args.w = net.w; - args.h = net.h; + args.w = net->w; + args.h = net->h; args.paths = paths; args.n = imgs; args.m = plist->size; @@ -43,7 +47,7 @@ void train_swag(char *cfgfile, char *weightfile) pthread_t load_thread = load_data_in_thread(args); clock_t time; //while(i*imgs < N*120){ - while(get_current_batch(net) < net.max_batches){ + while(get_current_batch(net) < net->max_batches){ i += 1; time=clock(); pthread_join(load_thread, 0); diff --git a/examples/voxel.c b/examples/voxel.c index 01ea9bb9..a8fcd54c 100644 --- a/examples/voxel.c +++ b/examples/voxel.c @@ -44,13 +44,13 @@ void train_voxel(char *cfgfile, char *weightfile) char *base = basecfg(cfgfile); printf("%s\n", base); float avg_loss = -1; - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net.learning_rate, net.momentum, net.decay); - int imgs = net.batch*net.subdivisions; - int i = *net.seen/imgs; + printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net->learning_rate, net->momentum, net->decay); + int imgs = net->batch*net->subdivisions; + int i = *net->seen/imgs; data train, buffer; @@ -59,8 +59,8 @@ void train_voxel(char *cfgfile, char *weightfile) char **paths = (char **)list_to_array(plist); load_args args = {0}; - args.w = net.w; - args.h = net.h; + args.w = net->w; + args.h = net->h; args.scale = 4; args.paths = paths; args.n = imgs; @@ -71,7 +71,7 @@ void train_voxel(char *cfgfile, char *weightfile) pthread_t load_thread = load_data_in_thread(args); clock_t time; //while(i*imgs < N*120){ - while(get_current_batch(net) < net.max_batches){ + while(get_current_batch(net) < net->max_batches){ i += 1; time=clock(); pthread_join(load_thread, 0); @@ -105,11 +105,11 @@ void train_voxel(char *cfgfile, char *weightfile) void test_voxel(char *cfgfile, char *weightfile, char *filename) { - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - set_batch_network(&net, 1); + set_batch_network(net, 1); srand(2222222); clock_t time; @@ -126,7 +126,7 @@ void test_voxel(char *cfgfile, char *weightfile, char *filename) strtok(input, "\n"); } image im = load_image_color(input, 0, 0); - resize_network(&net, im.w, im.h); + resize_network(net, im.w, im.h); printf("%d %d\n", im.w, im.h); float *X = im.data; diff --git a/examples/writing.c b/examples/writing.c index 1b6ff83b..f5d43630 100644 --- a/examples/writing.c +++ b/examples/writing.c @@ -7,12 +7,12 @@ void train_writing(char *cfgfile, char *weightfile) float avg_loss = -1; char *base = basecfg(cfgfile); printf("%s\n", base); - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net.learning_rate, net.momentum, net.decay); - int imgs = net.batch*net.subdivisions; + printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net->learning_rate, net->momentum, net->decay); + int imgs = net->batch*net->subdivisions; list *plist = get_paths("figures.list"); char **paths = (char **)list_to_array(plist); clock_t time; @@ -23,8 +23,8 @@ void train_writing(char *cfgfile, char *weightfile) data train, buffer; load_args args = {0}; - args.w = net.w; - args.h = net.h; + args.w = net->w; + args.h = net->h; args.out_w = out.w; args.out_h = out.h; args.paths = paths; @@ -34,8 +34,8 @@ void train_writing(char *cfgfile, char *weightfile) args.type = WRITING_DATA; pthread_t load_thread = load_data_in_thread(args); - int epoch = (*net.seen)/N; - while(get_current_batch(net) < net.max_batches || net.max_batches == 0){ + int epoch = (*net->seen)/N; + while(get_current_batch(net) < net->max_batches || net->max_batches == 0){ time=clock(); pthread_join(load_thread, 0); train = buffer; @@ -63,15 +63,15 @@ void train_writing(char *cfgfile, char *weightfile) if(avg_loss == -1) avg_loss = loss; avg_loss = avg_loss*.9 + loss*.1; - printf("%ld, %.3f: %f, %f avg, %f rate, %lf seconds, %ld images\n", get_current_batch(net), (float)(*net.seen)/N, loss, avg_loss, get_current_rate(net), sec(clock()-time), *net.seen); + printf("%ld, %.3f: %f, %f avg, %f rate, %lf seconds, %ld images\n", get_current_batch(net), (float)(*net->seen)/N, loss, avg_loss, get_current_rate(net), sec(clock()-time), *net->seen); free_data(train); if(get_current_batch(net)%100 == 0){ char buff[256]; sprintf(buff, "%s/%s_batch_%ld.weights", backup_directory, base, get_current_batch(net)); save_weights(net, buff); } - if(*net.seen/N > epoch){ - epoch = *net.seen/N; + if(*net->seen/N > epoch){ + epoch = *net->seen/N; char buff[256]; sprintf(buff, "%s/%s_%d.weights",backup_directory,base, epoch); save_weights(net, buff); @@ -81,11 +81,11 @@ void train_writing(char *cfgfile, char *weightfile) void test_writing(char *cfgfile, char *weightfile, char *filename) { - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - set_batch_network(&net, 1); + set_batch_network(net, 1); srand(2222222); clock_t time; char buff[256]; @@ -102,7 +102,7 @@ void test_writing(char *cfgfile, char *weightfile, char *filename) } image im = load_image_color(input, 0, 0); - resize_network(&net, im.w, im.h); + resize_network(net, im.w, im.h); printf("%d %d %d\n", im.h, im.w, im.c); float *X = im.data; time=clock(); diff --git a/general.pri b/general.pri new file mode 100644 index 00000000..27cb3060 --- /dev/null +++ b/general.pri @@ -0,0 +1,156 @@ +isEmpty(SOLUTION_DIR) { + SOLUTION_DIR = $$PWD +# warning("Variable \"SOLUTION_DIR\" is not defined, so the default value \"$$SOLUTION_DIR\" (the directory of \"general.pri\") will be used.") +} + + +isEmpty(SOLUTION_NAME) { + SOLUTION_NAME = $$basename(PWD) +# warning("Variable \"SOLUTION_NAME\" is not defined, so the default value \"$$SOLUTION_NAME\" (the directory name of \"general.pri\") will be used.") +} + + +isEmpty(PROJECT_DIR) { + PROJECT_DIR = $$_PRO_FILE_PWD_ +} + + +isEmpty(PROJECT_NAME) { + PROJECT_NAME = $$basename(_PRO_FILE_PWD_) +} + + +isEmpty(VERSION) { + VERSION = 0.0.0 + warning("Variable \"VERSION\" is not defined, so the default value \"0.0.0\" will be used.") +} + + +isEmpty(CONFIGURATION_NAME) { + CONFIG(debug, debug|release): CONFIGURATION_NAME = debug + else: CONFIGURATION_NAME = release +} + + +isEmpty(COMPILER_NAME) { + COMPILER_NAME = $$(COMPILER_NAME) + isEmpty(COMPILER_NAME) { + win32: COMPILER_NAME = msvc + else: COMPILER_NAME = gcc + } +} + + +isEmpty(ARCHITECTURE_NAME) { + ARCHITECTURE_NAME = $$(ARCHITECTURE_NAME) + isEmpty(ARCHITECTURE_NAME) { + ARCHITECTURE_NAME = x64 + } +} + + +isEmpty(TEMP_DIR) { + TEMP_DIR = $$(TEMP_DIR) + isEmpty(TEMP_DIR) { + win32: TEMP_DIR = E:/temp + else: TEMP_DIR = $$(HOME)/temp + } +} + + +isEmpty(DEST_ROOT) { + DEST_ROOT = $$(DEST_ROOT) + isEmpty(DEST_ROOT) { + DEST_ROOT = $$TEMP_DIR/$$SOLUTION_NAME/build/$$SOLUTION_NAME-$$VERSION-$$COMPILER_NAME-$$ARCHITECTURE_NAME + } +} + + +isEmpty(INSTALL_PREFIX) { + INSTALL_PREFIX = $$(INSTALL_PREFIX) + isEmpty(INSTALL_PREFIX) { + INSTALL_PREFIX = $$TEMP_DIR/$$SOLUTION_NAME/install/$$SOLUTION_NAME-$$VERSION-$$COMPILER_NAME-$$ARCHITECTURE_NAME + } +} + + +isEmpty(LIBS_ROOT) { + LIBS_ROOT = $$(LIBS_ROOT) + isEmpty(LIBS_ROOT) { + LIBS_ROOT = $$clean_path($$SOLUTION_DIR/../$$SOLUTION_NAME"_"ThirdParty) + } +} + + +isEmpty(OTHERFILES_ROOT) { + OTHERFILES_ROOT = $$(OTHERFILES_ROOT) + isEmpty(OTHERFILES_ROOT) { + OTHERFILES_ROOT = $$clean_path($$SOLUTION_DIR/../$$SOLUTION_NAME"_"OtherFiles) + } +} + + +win32 { + BUILD_DEPEND_LIB_DIR_NAME = lib + BUILD_DEPEND_LIB_FILE_SUFFIX_SHARED = "."lib + BUILD_DEPEND_LIB_FILE_SUFFIX_STATIC = "."lib + BUILD_DEPEND_LIB_FILE_SUFFIX = $$BUILD_DEPEND_LIB_FILE_SUFFIX_SHARED + INSTALL_DEPEND_LIB_DIR_NAME = bin + BUILD_OBJECT_FILE_SUFFIX = "."obj + INSTALL_DEPEND_LIB_FILE_SUFFIX = "."dll + + deployqt = windeployqt + + EXECUTABLE_FILE_SUFFIX = "."exe + EXECUTABLE_SCRIPT_FILE_SUFFIX = "."bat +} else { + BUILD_DEPEND_LIB_DIR_NAME = lib + BUILD_DEPEND_LIB_FILE_SUFFIX_SHARED = "."so + BUILD_DEPEND_LIB_FILE_SUFFIX_STATIC = "."a + BUILD_DEPEND_LIB_FILE_SUFFIX = $$BUILD_DEPEND_LIB_FILE_SUFFIX_SHARED + BUILD_OBJECT_FILE_SUFFIX = "."o + INSTALL_DEPEND_LIB_DIR_NAME = lib + INSTALL_DEPEND_LIB_FILE_SUFFIX = "."so + + deployqt = linuxdeployqt + + EXECUTABLE_FILE_SUFFIX = + EXECUTABLE_SCRIPT_FILE_SUFFIX = "."sh +} + + +defineReplace(getInstallDeployQtCommand) { + TARGET_ = $$1 + win32 { + return($$deployqt --dir $$INSTALL_PREFIX --libdir $$INSTALL_PREFIX/lib/Qt --plugindir $$INSTALL_PREFIX/plugins $$INSTALL_PREFIX/bin/$$TARGET_$$EXECUTABLE_FILE_SUFFIX) + } else { + LIBS_ = $$2 + DEPEND_LIB_PATHS = + for (lib_dir, LIBS_) { + lib_dir = $$replace(lib_dir, -L, "") + exists($$lib_dir/*) { + DEPEND_LIB_PATHS += $$lib_dir + } + } + setup_env = $$join(DEPEND_LIB_PATHS, ":", "export LD_LIBRARY_PATH=\"", ":$LD_LIBRARY_PATH\"") + + return($$setup_env; $$deployqt $$INSTALL_PREFIX/bin/$$TARGET_$$EXECUTABLE_FILE_SUFFIX) + } +} + + +isEmpty(DEFINED_TARGET) { + CONFIG(debug, debug|release): TARGET = $$PROJECT_NAME"d" + else: TARGET = $$PROJECT_NAME + + DEFINED_TARGET = 1 +} +isEmpty(DEFINED_DESTDIR) { + equals(TEMPLATE, "lib") { + DESTDIR = $$DEST_ROOT/$$PROJECT_NAME/lib + } else: equals(TEMPLATE, "app") { + DESTDIR = $$DEST_ROOT/$$PROJECT_NAME/bin + } + + DEFINED_DESTDIR = 1 +} diff --git a/src/compare.c b/src/compare.c index d2d2b3bd..d1dd9341 100644 --- a/src/compare.c +++ b/src/compare.c @@ -14,11 +14,11 @@ void train_compare(char *cfgfile, char *weightfile) char *base = basecfg(cfgfile); char *backup_directory = "/home/pjreddie/backup/"; printf("%s\n", base); - network net = parse_network_cfg(cfgfile); + network *net = parse_network_cfg(cfgfile); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } - printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net.learning_rate, net.momentum, net.decay); + printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net->learning_rate, net->momentum, net->decay); int imgs = 1024; list *plist = get_paths("data/compare.train.list"); char **paths = (char **)list_to_array(plist); @@ -30,8 +30,8 @@ void train_compare(char *cfgfile, char *weightfile) data buffer; load_args args = {0}; - args.w = net.w; - args.h = net.h; + args.w = net->w; + args.h = net->h; args.paths = paths; args.classes = 20; args.n = imgs; @@ -40,7 +40,7 @@ void train_compare(char *cfgfile, char *weightfile) args.type = COMPARE_DATA; load_thread = load_data_in_thread(args); - int epoch = *net.seen/N; + int epoch = *net->seen/N; int i = 0; while(1){ ++i; @@ -54,20 +54,20 @@ void train_compare(char *cfgfile, char *weightfile) float loss = train_network(net, train); if(avg_loss == -1) avg_loss = loss; avg_loss = avg_loss*.9 + loss*.1; - printf("%.3f: %f, %f avg, %lf seconds, %ld images\n", (float)*net.seen/N, loss, avg_loss, sec(clock()-time), *net.seen); + printf("%.3f: %f, %f avg, %lf seconds, %ld images\n", (float)*net->seen/N, loss, avg_loss, sec(clock()-time), *net->seen); free_data(train); if(i%100 == 0){ char buff[256]; sprintf(buff, "%s/%s_%d_minor_%d.weights",backup_directory,base, epoch, i); save_weights(net, buff); } - if(*net.seen/N > epoch){ - epoch = *net.seen/N; + if(*net->seen/N > epoch){ + epoch = *net->seen/N; i = 0; char buff[256]; sprintf(buff, "%s/%s_%d.weights",backup_directory,base, epoch); save_weights(net, buff); - if(epoch%22 == 0) net.learning_rate *= .1; + if(epoch%22 == 0) net->learning_rate *= .1; } } pthread_join(load_thread, 0); @@ -81,9 +81,9 @@ void train_compare(char *cfgfile, char *weightfile) void validate_compare(char *filename, char *weightfile) { int i = 0; - network net = parse_network_cfg(filename); + network *net = parse_network_cfg(filename); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } srand(time(0)); @@ -102,8 +102,8 @@ void validate_compare(char *filename, char *weightfile) data val, buffer; load_args args = {0}; - args.w = net.w; - args.h = net.h; + args.w = net->w; + args.h = net->h; args.paths = paths; args.classes = 20; args.n = num; @@ -146,7 +146,7 @@ void validate_compare(char *filename, char *weightfile) } typedef struct { - network net; + network *net; char *filename; int class; int classes; @@ -171,12 +171,12 @@ int bbox_comparator(const void *a, const void *b) ++total_compares; sortable_bbox box1 = *(sortable_bbox*)a; sortable_bbox box2 = *(sortable_bbox*)b; - network net = box1.net; + network *net = box1.net; int class = box1.class; - image im1 = load_image_color(box1.filename, net.w, net.h); - image im2 = load_image_color(box2.filename, net.w, net.h); - float *X = calloc(net.w*net.h*net.c, sizeof(float)); + image im1 = load_image_color(box1.filename, net->w, net->h); + image im2 = load_image_color(box2.filename, net->w, net->h); + float *X = calloc(net->w*net->h*net->c, sizeof(float)); memcpy(X, im1.data, im1.w*im1.h*im1.c*sizeof(float)); memcpy(X+im1.w*im1.h*im1.c, im2.data, im2.w*im2.h*im2.c*sizeof(float)); float *predictions = network_predict(net, X); @@ -201,11 +201,11 @@ void bbox_update(sortable_bbox *a, sortable_bbox *b, int class, int result) b->elos[class] += k*(SB - EB); } -void bbox_fight(network net, sortable_bbox *a, sortable_bbox *b, int classes, int class) +void bbox_fight(network *net, sortable_bbox *a, sortable_bbox *b, int classes, int class) { - image im1 = load_image_color(a->filename, net.w, net.h); - image im2 = load_image_color(b->filename, net.w, net.h); - float *X = calloc(net.w*net.h*net.c, sizeof(float)); + image im1 = load_image_color(a->filename, net->w, net->h); + image im2 = load_image_color(b->filename, net->w, net->h); + float *X = calloc(net->w*net->h*net->c, sizeof(float)); memcpy(X, im1.data, im1.w*im1.h*im1.c*sizeof(float)); memcpy(X+im1.w*im1.h*im1.c, im2.data, im2.w*im2.h*im2.c*sizeof(float)); float *predictions = network_predict(net, X); @@ -227,12 +227,12 @@ void bbox_fight(network net, sortable_bbox *a, sortable_bbox *b, int classes, in void SortMaster3000(char *filename, char *weightfile) { int i = 0; - network net = parse_network_cfg(filename); + network *net = parse_network_cfg(filename); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } srand(time(0)); - set_batch_network(&net, 1); + set_batch_network(net, 1); list *plist = get_paths("data/compare.sort.list"); //list *plist = get_paths("data/compare.val.old"); @@ -259,12 +259,12 @@ void BattleRoyaleWithCheese(char *filename, char *weightfile) { int classes = 20; int i,j; - network net = parse_network_cfg(filename); + network *net = parse_network_cfg(filename); if(weightfile){ - load_weights(&net, weightfile); + load_weights(net, weightfile); } srand(time(0)); - set_batch_network(&net, 1); + set_batch_network(net, 1); list *plist = get_paths("data/compare.sort.list"); //list *plist = get_paths("data/compare.small.list"); diff --git a/src/convolutional_layer.h b/src/convolutional_layer.h index 6c261f5f..d3b7d93d 100644 --- a/src/convolutional_layer.h +++ b/src/convolutional_layer.h @@ -27,7 +27,7 @@ void cudnn_convolutional_setup(layer *l); convolutional_layer make_convolutional_layer(int batch, int h, int w, int c, int n, int groups, int size, int stride, int padding, ACTIVATION activation, int batch_normalize, int binary, int xnor, int adam); void resize_convolutional_layer(convolutional_layer *layer, int w, int h); -void forward_convolutional_layer(const convolutional_layer layer, network net); +void forward_convolutional_layer(convolutional_layer layer, network net); void update_convolutional_layer(convolutional_layer layer, update_args a); image *visualize_convolutional_layer(convolutional_layer layer, char *window, image *prev_weights); void binarize_weights(float *weights, int n, int size, float *binary); diff --git a/src/cost_layer.c b/src/cost_layer.c index 2138ff26..bd258ba3 100644 --- a/src/cost_layer.c +++ b/src/cost_layer.c @@ -98,7 +98,7 @@ void forward_cost_layer(cost_layer l, network net) l.cost[0] = sum_array(l.output, l.batch*l.inputs); } -void backward_cost_layer(const cost_layer l, network net) +void backward_cost_layer(cost_layer l, network net) { axpy_cpu(l.batch*l.inputs, l.scale, l.delta, 1, net.delta, 1); } diff --git a/src/cost_layer.h b/src/cost_layer.h index ceb64de0..3f161fc8 100644 --- a/src/cost_layer.h +++ b/src/cost_layer.h @@ -8,8 +8,8 @@ typedef layer cost_layer; COST_TYPE get_cost_type(char *s); char *get_cost_string(COST_TYPE a); cost_layer make_cost_layer(int batch, int inputs, COST_TYPE type, float scale); -void forward_cost_layer(const cost_layer l, network net); -void backward_cost_layer(const cost_layer l, network net); +void forward_cost_layer(cost_layer l, network net); +void backward_cost_layer(cost_layer l, network net); void resize_cost_layer(cost_layer *l, int inputs); #ifdef GPU diff --git a/src/demo.c b/src/demo.c index 492c360d..e5a74a4b 100644 --- a/src/demo.c +++ b/src/demo.c @@ -7,7 +7,11 @@ #include "box.h" #include "image.h" #include "demo.h" +#ifdef WIN32 +#include +#else #include +#endif #define DEMO 1 diff --git a/src/utils.c b/src/utils.c index 626b4678..8e2d13ff 100644 --- a/src/utils.c +++ b/src/utils.c @@ -3,11 +3,22 @@ #include #include #include +#ifdef WIN32 +#include +#else #include +#endif #include #include #include +#ifdef WIN32 +#include +#else #include +#endif +#ifdef WIN32 +#include +#endif #include "utils.h" @@ -78,7 +89,7 @@ void sorta_shuffle(void *arr, size_t n, size_t size, size_t sections) size_t start = n*i/sections; size_t end = n*(i+1)/sections; size_t num = end-start; - shuffle(arr+(start*size), num, size); + shuffle((char*)arr+(start*size), num, size); } } @@ -88,9 +99,9 @@ void shuffle(void *arr, size_t n, size_t size) void *swp = calloc(1, size); for(i = 0; i < n-1; ++i){ size_t j = i + rand()/(RAND_MAX / (n-i)+1); - memcpy(swp, arr+(j*size), size); - memcpy(arr+(j*size), arr+(i*size), size); - memcpy(arr+(i*size), swp, size); + memcpy(swp, (char*)arr+(j*size), size); + memcpy((char*)arr+(j*size), (char*)arr+(i*size), size); + memcpy((char*)arr+(i*size), swp, size); } } @@ -363,6 +374,7 @@ char *fgetl(FILE *fp) return line; } +#ifndef WIN32 int read_int(int fd) { int n = 0; @@ -418,7 +430,7 @@ void write_all(int fd, char *buffer, size_t bytes) n += next; } } - +#endif char *copy_string(char *s) { diff --git a/src/utils.h b/src/utils.h index ef24da79..daa9d3a3 100644 --- a/src/utils.h +++ b/src/utils.h @@ -20,12 +20,14 @@ void sorta_shuffle(void *arr, size_t n, size_t size, size_t sections); void free_ptrs(void **ptrs, int n); int alphanum_to_int(char c); char int_to_alphanum(int i); +#ifndef WIN32 int read_int(int fd); void write_int(int fd, int n); void read_all(int fd, char *buffer, size_t bytes); void write_all(int fd, char *buffer, size_t bytes); int read_all_fail(int fd, char *buffer, size_t bytes); int write_all_fail(int fd, char *buffer, size_t bytes); +#endif void find_replace(char *str, char *orig, char *rep, char *output); void malloc_error(); void file_error(char *s); diff --git a/windows/gettimeofday.c b/windows/gettimeofday.c new file mode 100644 index 00000000..4640d195 --- /dev/null +++ b/windows/gettimeofday.c @@ -0,0 +1,49 @@ +#include "gettimeofday.h" + + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + // converting file time to unix epoch + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tmpres /= 10; // convert into microseconds + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} + +int timersub(struct timeval *a, struct timeval *b, struct timeval *result) +{ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; + if ((result)->tv_usec < 0) { + --(result)->tv_sec; + (result)->tv_usec += 1000000; + } + + return 0; +} diff --git a/windows/gettimeofday.h b/windows/gettimeofday.h new file mode 100644 index 00000000..5eeca85f --- /dev/null +++ b/windows/gettimeofday.h @@ -0,0 +1,26 @@ +#ifndef GETTIMEOFDAY_H +#define GETTIMEOFDAY_H + +#include +#include + +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) +#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else +#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + + +struct timezone +{ + int tz_minuteswest; // minutes W of Greenwich + int tz_dsttime; // type of dst correction +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz); + +// never worry about timersub type activies again -- from GLIBC and upcased. +int timersub(struct timeval *a, struct timeval *b, struct timeval *result); + + +#endif