[conv] support dilation property
[platform/core/ml/nntrainer.git] / packaging / nntrainer.spec
1 # Execute gbs with --define "testcoverage 1" in case that you must get unittest coverage statistics
2 %define         use_cblas 1
3 %define         nnstreamer_filter 1
4 %define         nnstreamer_subplugin_path /usr/lib/nnstreamer
5 %define         use_gym 0
6 %define         support_ccapi 1
7 %define         support_nnstreamer_backbone 1
8 %define         support_tflite_backbone 1
9 %define         support_tflite_interpreter 1
10 %define         nntrainerapplicationdir %{_libdir}/nntrainer/bin
11 %define         gen_input $(pwd)/test/input_gen/genInput.py
12 %define         support_data_augmentation_opencv 1
13 %define         configure_subplugin_install_path -Dnnstreamer-subplugin-install-path=%{nnstreamer_subplugin_path}
14
15 %bcond_with tizen
16
17 # dependency resolution
18 %if 0%{tizen_version_major}%{tizen_version_minor} >= 65
19 # (rpm -qi nnstreamer --queryformat '%%{VERSION}' | sed -e 's/\.//g') >= 171
20
21 %define         capi_machine_learning_common       capi-machine-learning-common
22 %define         capi_machine_learning_inference  capi-machine-learning-inference
23
24 %define         capi_ml_common_pkg_name          capi-ml-common
25 %define         capi_ml_inference_pkg_name       capi-ml-inference
26
27 %else
28
29 %if 0%{tizen_version_major}%{tizen_version_minor} >= 60
30 # (rpm -qi nnstreamer --queryformat '%%{VERSION}' | sed -e 's/\.//g') >= 160
31 %define         capi_machine_learning_common     capi-ml-common
32 %define         capi_machine_learning_inference  capi-nnstreamer
33
34 %define         capi_ml_common_pkg_name          capi-nnstreamer
35 %define         capi_ml_inference_pkg_name       capi-nnstreamer
36 %else
37 %{error: nnst_version < 6.0 is not supported}
38 # shouldn't reach here. Below is for the reference.
39 # If you prepare ml-common-api.h, below can work though.
40 %define         capi_machine_learning_inference  capi-nnstreamer
41 %define         capi_machine_learning_common       capi-nnstreamer
42
43 %define         capi_ml_common_pkg_name          capi-nnstreamer
44 %define         capi_ml_inference_pkg_name       capi-nnstreamer
45 %endif # 0%{tizen_version_major}%{tizen_version_minor} >= 60
46
47 %endif # 0%{tizen_version_major}%{tizen_version_minor} >= 65
48
49 Name:           nntrainer
50 Summary:        Software framework for training neural networks
51 Version:        0.3.0
52 Release:        0
53 Packager:       Jijoong Moon <jijoong.moon@samsung.com>
54 License:        Apache-2.0
55 Source0:        nntrainer-%{version}.tar.gz
56 Source1001:     nntrainer.manifest
57 %if %{with tizen}
58 Source1002:     capi-machine-learning-training.manifest
59 %endif
60 Source2001:     trainset.tar.gz
61 Source2002:     valset.tar.gz
62 Source2003:     testset.tar.gz
63 Source2004:     label.dat
64 Source2005:     unittest_layers.tar.gz
65
66 BuildRequires:  meson >= 0.50.0
67 BuildRequires:  openblas-devel
68 BuildRequires:  iniparser-devel >= 4.1
69 BuildRequires:  gtest-devel
70 BuildRequires:  python3
71 BuildRequires:  python3-numpy
72 BuildRequires:  flatbuffers-devel
73
74 BuildRequires:  %{capi_machine_learning_common}-devel
75 BuildRequires:  %{capi_machine_learning_inference}-devel
76
77 %if 0%{?unit_test}
78 BuildRequires:  ssat >= 1.1.0
79 %endif
80
81 # OpenAI interface
82 %define enable_gym -Duse_gym=false
83 %if 0%{?use_gym}
84 BuildRequires:  gym-http-api-devel
85 %define enable_gym -Duse_gym=true
86 %endif
87
88 %if 0%{?testcoverage}
89 # to be compatible with gcc-9, lcov should have a higher version than 1.14.1
90 BuildRequires: lcov
91 # BuildRequires:        taos-ci-unittest-coverage-assessment
92 %endif
93
94 %if 0%{?support_data_augmentation_opencv}
95 BuildRequires: opencv-devel
96 %endif
97
98 %if %{with tizen}
99 BuildRequires:  pkgconfig(capi-system-info)
100 BuildRequires:  pkgconfig(capi-base-common)
101 BuildRequires:  pkgconfig(dlog)
102
103 %if 0%{?support_nnstreamer_backbone}
104 BuildRequires: nnstreamer-tensorflow2-lite
105
106 Requires:       nnstreamer-tensorflow2-lite
107 %endif # support_nnstreamer_backbone
108
109 %if 0%{?support_tflite_backbone}
110 BuildRequires: tensorflow2-lite-devel
111 %endif # support_tflite_backbone
112
113 %if 0%{?support_tflite_interpreter}
114 BuildRequires: tensorflow2-lite-devel
115 %endif # support_tflite_interpreter
116
117 %define enable_nnstreamer_tensor_filter -Denable-nnstreamer-tensor-filter=false
118
119 %if  0%{?nnstreamer_filter}
120 BuildRequires:  nnstreamer-devel
121 %define enable_nnstreamer_tensor_filter -Denable-nnstreamer-tensor-filter=true
122
123 %if 0%{?unit_test}
124 %if 0%{tizen_version_major}%{tizen_version_minor} > 60
125 BuildRequires:  nnstreamer-test-devel
126 %endif
127 BuildRequires:  gst-plugins-good-extra
128 BuildRequires:  python
129 %endif #unit_test
130 %endif #nnstreamer_filter
131 %endif  # tizen
132
133 Requires:       nntrainer-core = %{version}-%{release}
134
135 %if 0%{?nnstreamer_filter}
136 Requires:       nnstreamer-nntrainer = %{version}-%{release}
137 %endif #nnstreamer_filter
138 %if %{with tizen}
139 Requires:       capi-machine-learning-training = %{version}-%{release}
140 %endif #tizen
141
142 %description
143 NNtrainer Meta package for tizen
144
145 %package core
146 Summary:        Software framework for training neural networks
147 Requires:       iniparser >= 4.1
148 Requires:       libopenblas_pthreads0
149
150 %description core
151 NNtrainer is Software Framework for Training Neural Network Models on Devices.
152
153 %package devel
154 Summary:        Development package for custom nntrainer developers
155 Requires:       nntrainer = %{version}-%{release}
156 Requires:       openblas-devel
157 Requires:       %{capi_machine_learning_common}-devel
158
159 %description devel
160 Development package for custom nntrainer developers.
161 This contains corresponding header files and .pc pkgconfig file.
162
163 %package devel-static
164 Summary:        Static library for nntrainer-devel package
165 Requires:       nntrainer-devel = %{version}-%{release}
166 %description devel-static
167 Static library package of nntrainer-devel
168
169 %package applications
170 Summary:        NNTrainer Examples
171 Requires:       nntrainer = %{version}-%{release}
172 Requires:       %{capi_machine_learning_inference}
173 Requires:       nnstreamer-tensorflow2-lite
174 %if 0%{tizen_version_major}%{tizen_version_minor} > 60
175 BuildRequires:  nnstreamer-test-devel
176 %endif
177 BuildRequires:  nnstreamer-tensorflow2-lite
178 BuildRequires:  tensorflow2-lite-devel
179 BuildRequires:  pkgconfig(jsoncpp)
180 BuildRequires:  pkgconfig(libcurl)
181 BuildRequires:  pkgconfig(dlog)
182 BuildRequires:  %{capi_machine_learning_inference}-devel
183 BuildRequires:  glib2-devel
184 BuildRequires:  gstreamer-devel
185
186 %description applications
187 NNTrainer Examples for test purpose.
188
189 # gcov
190 %if 0%{?gcov:1}
191 %package gcov
192 Summary:         NNTrainer gcov
193 Group:           Machine Learning/ML Framework
194
195 %description gcov
196 NNTrainer gcov object
197 %endif
198
199 %if 0%{?testcoverage}
200 %package unittest-coverage
201 Summary:        NNTrainer UnitTest Coverage Analysis Result
202
203 %description unittest-coverage
204 HTML pages of lcov results of NNTrainer generated during rpmbuild
205 %endif
206
207 %if %{with tizen}
208 %package -n capi-machine-learning-training
209 Summary:         Tizen Native API for NNTrainer
210 Group:           Machine Learning/ML Framework
211 Requires:        %{name} = %{version}-%{release}
212 %description -n capi-machine-learning-training
213 Tizen Native API wrapper for NNTrainer.
214 You can train neural networks efficiently.
215
216 %post -n capi-machine-learning-training -p /sbin/ldconfig
217 %postun -n capi-machine-learning-training -p /sbin/ldconfig
218
219 %package -n capi-machine-learning-training-devel
220 Summary:         Tizen Native API Devel Kit for NNTrainer
221 Group:           Machine Learning/ML Framework
222 Requires:        capi-machine-learning-training = %{version}-%{release}
223 Requires:        %{capi_machine_learning_common}-devel
224 %description -n capi-machine-learning-training-devel
225 Developmental kit for Tizen Native NNTrainer API.
226
227 %package -n capi-machine-learning-training-devel-static
228 Summary:         Static library for Tizen Native API
229 Group:           Machine Learning/ML Framework
230 Requires:        capi-machine-learning-training-devel = %{version}-%{release}
231 %description -n capi-machine-learning-training-devel-static
232 Static library of capi-machine-learning-training-devel package.
233
234 %package tizen-internal-devel
235 Summary:        Tizen internal headers for Tizen Machine Learning Training API
236 Group:          Machine Learning/ML Framework
237 Requires:       capi-machine-learning-training-devel = %{version}-%{release}
238 %description tizen-internal-devel
239 Tizen internal headers for Tizen Machine Learning Training API.
240
241 %if 0%{?support_ccapi}
242 %package -n ccapi-machine-learning-training
243 Summary:         Tizen Native API for NNTrainer
244 Group:           Machine Learning/ML Framework
245 Requires:        %{name} = %{version}-%{release}
246 %description -n ccapi-machine-learning-training
247 Tizen Native API wrapper for NNTrainer.
248 You can train neural networks efficiently.
249
250 %post -n ccapi-machine-learning-training -p /sbin/ldconfig
251 %postun -n ccapi-machine-learning-training -p /sbin/ldconfig
252
253 %package -n ccapi-machine-learning-training-devel
254 Summary:         Tizen Native API Devel Kit for NNTrainer
255 Group:           Machine Learning/ML Framework
256 Requires:        ccapi-machine-learning-training = %{version}-%{release}
257 %description -n ccapi-machine-learning-training-devel
258 Developmental kit for Tizen Native NNTrainer API.
259
260 %package -n ccapi-machine-learning-training-devel-static
261 Summary:         Static library for Tizen c++ API
262 Group:           Machine Learning/ML Framework
263 Requires:        ccapi-machine-learning-training-devel = %{version}-%{release}
264 %description -n ccapi-machine-learning-training-devel-static
265 Static library of ccapi-machine-learning-training-devel package.
266 %endif
267
268 %if 0%{?nnstreamer_filter}
269 %package -n nnstreamer-nntrainer
270 Summary: NNStreamer NNTrainer support
271 Requires: %{name} = %{version}-%{release}
272 Requires:       nnstreamer
273 %description -n nnstreamer-nntrainer
274 NNSteamer tensor filter for nntrainer to support inference.
275
276 %package -n nnstreamer-nntrainer-devel-static
277 Summary: NNStreamer NNTrainer support
278 Requires: nntrainer-devel-static = %{version}-%{release}
279 Requires:       nnstreamer-nntrainer = %{version}-%{release}
280 %description -n nnstreamer-nntrainer-devel-static
281 NNSteamer tensor filter static package for nntrainer to support inference.
282 %endif #nnstreamer_filter
283
284 %endif #tizen
285
286 ## Define build options
287 %define platform -Dplatform=tizen
288 %define enable_tizen_feature_check -Denable-tizen-feature-check=true -Dtizen-version-major=0%{?tizen_version_major} -Dtizen-version-minor=0%{?tizen_version_minor}
289 %define install_app -Dinstall-app=true
290 %define enable_ccapi -Denable-ccapi=false
291 %define enable_nnstreamer_backbone -Denable-nnstreamer-backbone=false
292 %define enable_tflite_backbone -Denable-tflite-backbone=false
293 %define enable_tflite_interpreter -Denable-tflite-interpreter=false
294 %define enable_profile -Denable-profile=false
295 %define capi_ml_pkg_dep_resolution -Dcapi-ml-inference-actual=%{?capi_ml_inference_pkg_name} -Dcapi-ml-common-actual=%{?capi_ml_common_pkg_name}
296 %define enable_reduce_tolerance -Dreduce-tolerance=true
297 %define enable_debug -Denable-debug=false
298
299 # enable full tolerance on the CI
300 %if 0%{?unit_test}
301 %define enable_reduce_tolerance -Dreduce-tolerance=false
302 %endif
303
304 # enable debug on the CI for build
305 %if 0%{?unit_test}
306 %define enable_debug -Denable-debug=true
307 %endif
308
309 %if %{with tizen}
310 %define platform -Dplatform=tizen
311
312 %if 0%{?support_ccapi}
313 %define enable_ccapi -Denable-ccapi=true
314 %endif # support_ccapi
315 %endif # tizen
316
317 # Using cblas for Matrix calculation
318 %if 0%{?use_cblas}
319 %define enable_cblas -Denable-blas=true
320 %endif
321
322 %if 0%{?support_nnstreamer_backbone}
323 %define enable_nnstreamer_backbone -Denable-nnstreamer-backbone=true
324 %endif
325
326 %if 0%{?support_tflite_backbone}
327 %define enable_tflite_backbone -Denable-tflite-backbone=true
328 %endif
329
330 %if 0%{?unit_test}
331 %define enable_profile -Denable-profile=true
332 %endif
333
334 %if 0%{?support_tflite_interpreter}
335 %define enable_tflite_interpreter -Denable-tflite-interpreter=true
336 %endif
337
338 %prep
339 %setup -q
340 cp %{SOURCE1001} .
341 cp %{SOURCE2001} .
342 cp %{SOURCE2002} .
343 cp %{SOURCE2003} .
344 cp %{SOURCE2004} .
345 cp %{SOURCE2005} .
346
347 %if %{with tizen}
348 cp %{SOURCE1002} .
349 %endif
350
351 %build
352 CXXFLAGS=`echo $CXXFLAGS | sed -e "s|-std=gnu++11||"`
353
354 %if 0%{?testcoverage} || 0%{?gcov:1}
355 export CFLAGS+=" -fprofile-arcs -ftest-coverage"
356 export CXXFLAGS+=" -fprofile-arcs -ftest-coverage"
357 %endif
358
359 # Add backward competibility for tizen < 6
360 %if 0%{tizen_version_major} < 6
361 ln -sf %{_includedir}/nnstreamer/nnstreamer.h %{_includedir}/nnstreamer/ml-api-common.h
362 ln -sf %{_libdir}/pkgconfig/capi-nnstreamer.pc %{_libdir}/pkgconfig/capi-ml-common.pc
363 %endif
364
365 mkdir -p build
366 meson --buildtype=plain --prefix=%{_prefix} --sysconfdir=%{_sysconfdir} \
367       --libdir=%{_libdir} --bindir=%{nntrainerapplicationdir} \
368       --includedir=%{_includedir} %{install_app} %{platform} \
369       %{enable_tizen_feature_check} %{enable_cblas} %{enable_ccapi} \
370       %{enable_gym} %{enable_nnstreamer_tensor_filter} %{enable_profile} \
371       %{enable_nnstreamer_backbone} %{enable_tflite_backbone} \
372       %{enable_tflite_interpreter} %{capi_ml_pkg_dep_resolution} \
373       %{enable_reduce_tolerance} %{configure_subplugin_install_path} %{enable_debug} \
374       -Dml-api-support=enabled -Denable-nnstreamer-tensor-filter=true \
375       -Denable-capi=enabled \
376       build
377
378 ninja -C build %{?_smp_mflags}
379
380 %if 0%{?unit_test}
381 export NNSTREAMER_CONF=$(pwd)/test/nnstreamer/nnstreamer-test.ini
382 export NNSTREAMER_FILTERS=$(pwd)/build/nnstreamer/tensor_filter
383 meson test -C build -t 2.0 --print-errorlogs
384
385 # unittest for nntrainer plugin for nnstreamer
386 # todo: migrate this to meson test soon
387 %if 0%{?nnstreamer_filter}
388 pushd test/nnstreamer
389 ssat
390 popd
391 %endif #nnstreamer_filter
392 %endif #unit_test
393
394 %if 0%{?gcov:1}
395 mkdir -p gcov-obj
396 find . -name '*.gcno' -exec cp '{}' gcov-obj ';'
397 %endif
398
399 %install
400 DESTDIR=%{buildroot} ninja -C build %{?_smp_mflags} install
401
402 %if 0%{?gcov:1}
403 mkdir -p %{buildroot}%{_datadir}/gcov/obj/%{name}
404 install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj/%{name}
405 %endif
406
407 %if 0%{?testcoverage}
408 ##
409 # The included directories are:
410 #
411 # api: nnstreamer api
412 # gst: the nnstreamer elements
413 # nnstreamer_example: custom plugin examples
414 # common: common libraries for gst (elements)
415 # include: common library headers and headers for external code (packaged as "devel")
416 #
417 # Intentionally excluded directories are:
418 #
419 # tests: We are not going to show testcoverage of the test code itself or example applications
420
421 %if %{with tizen}
422 %define testtarget $(pwd)/api/capi
423 %else
424 %define testtarget
425 %endif
426
427 # 'lcov' generates the date format with UTC time zone by default. Let's replace UTC with KST.
428 # If you ccan get a root privilege, run ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
429 TZ='Asia/Seoul'; export TZ
430 $(pwd)/test/unittestcoverage.py module $(pwd)/nntrainer %testtarget
431
432 # Get commit info
433 VCS=`cat ${RPM_SOURCE_DIR}/nntrainer.spec | grep "^VCS:" | sed "s|VCS:\\W*\\(.*\\)|\\1|"`
434
435 # Create human readable unit test coverage report web page.
436 # Create null gcda files if gcov didn't create it because there is completely no unit test for them.
437 find . -name "*.gcno" -exec sh -c 'touch -a "${1%.gcno}.gcda"' _ {} \;
438 # Remove gcda for meaningless file (CMake's autogenerated)
439 find . -name "CMakeCCompilerId*.gcda" -delete
440 find . -name "CMakeCXXCompilerId*.gcda" -delete
441 #find . -path "/build/*.j
442
443 # Generate report
444 lcov -t 'NNTrainer Unit Test Coverage' -o unittest.info -c -d . -b %{_builddir}/%{name}-%{version}/build \
445     --include "*/nntrainer/*" \
446     --include "*/api/*" \
447     --exclude "*/tensorflow*" \
448     --exclude "*/Applications/*" \
449     --exclude "*/test/*" \
450     --exclude "*/meson*/*" \
451     --exclude "*/nntrainer_logger.cpp" \
452     --exclude "*/tf_schema_generated.h" \
453     --exclude "*/nnstreamer_layer.*"
454 # nnstreamer layer is untestable here
455
456 # Visualize the report
457 genhtml -o result unittest.info -t "nntrainer %{version}-%{release} ${VCS}" --ignore-errors source -p ${RPM_BUILD_DIR}
458
459 mkdir -p %{buildroot}%{_datadir}/nntrainer/unittest/
460 cp -r result %{buildroot}%{_datadir}/nntrainer/unittest/
461 %endif  # test coverage
462
463 %post -p /sbin/ldconfig
464 %postun -p /sbin/ldconfig
465
466 %files
467
468 %files core
469 %manifest nntrainer.manifest
470 %defattr(-,root,root,-)
471 %license LICENSE
472 %{_libdir}/libnntrainer.so
473 %config %{_sysconfdir}/nntrainer.ini
474
475 %files devel
476 # node exporter and its dependencies
477 %{_includedir}/nntrainer/nntrainer_error.h
478 %{_includedir}/nntrainer/connection.h
479 %{_includedir}/nntrainer/common_properties.h
480 %{_includedir}/nntrainer/base_properties.h
481 %{_includedir}/nntrainer/node_exporter.h
482 # tensor headers
483 %{_includedir}/nntrainer/tensor.h
484 %{_includedir}/nntrainer/tensor_wrap_specs.h
485 # @todo: update dataset headers
486 %{_includedir}/nntrainer/databuffer.h
487 %{_includedir}/nntrainer/databuffer_factory.h
488 # layer headers
489 %{_includedir}/nntrainer/layer_context.h
490 %{_includedir}/nntrainer/layer_devel.h
491 %{_includedir}/nntrainer/layer_impl.h
492 # custom layer kits
493 %{_includedir}/nntrainer/app_context.h
494 # optimizer headers
495 %{_includedir}/nntrainer/optimizer_context.h
496 %{_includedir}/nntrainer/optimizer_devel.h
497 %{_includedir}/nntrainer/lr_scheduler.h
498 %{_libdir}/pkgconfig/nntrainer.pc
499 # update this to enable external applications
500 # @todo filter out headers that should be hidden, and classifiy in the appropriate place if not
501 %{_includedir}/nntrainer/util_func.h
502
503 %files devel-static
504 %{_libdir}/libnntrainer*.a
505 %exclude %{_libdir}/libcapi*.a
506
507 %if %{with tizen}
508 %files -n capi-machine-learning-training
509 %manifest capi-machine-learning-training.manifest
510 %license LICENSE
511 %{_libdir}/libcapi-nntrainer.so
512
513 %files -n capi-machine-learning-training-devel
514 %{_includedir}/nntrainer/nntrainer.h
515 %{_includedir}/nntrainer/nntrainer-api-common.h
516 %{_libdir}/pkgconfig/capi-ml-training.pc
517
518 %files -n capi-machine-learning-training-devel-static
519 %{_libdir}/libcapi-nntrainer.a
520
521 %files tizen-internal-devel
522 %{_includedir}/nntrainer/nntrainer-tizen-internal.h
523
524 %if 0%{?support_ccapi}
525 %files -n ccapi-machine-learning-training
526 %manifest capi-machine-learning-training.manifest
527 %license LICENSE
528 %{_libdir}/libccapi-nntrainer.so
529
530 %files -n ccapi-machine-learning-training-devel
531 %{_includedir}/nntrainer/common.h
532 %{_includedir}/nntrainer/model.h
533 %{_includedir}/nntrainer/layer.h
534 %{_includedir}/nntrainer/optimizer.h
535 %{_includedir}/nntrainer/dataset.h
536 %{_includedir}/nntrainer/tensor_dim.h
537 %{_libdir}/pkgconfig/ccapi-ml-training.pc
538
539 %files -n ccapi-machine-learning-training-devel-static
540 %{_libdir}/libccapi-nntrainer.a
541 %endif # support_ccapi
542
543 %if 0%{?nnstreamer_filter}
544 %files -n nnstreamer-nntrainer
545 %manifest nntrainer.manifest
546 %defattr(-,root,root,-)
547 %license LICENSE
548 %{nnstreamer_subplugin_path}/filters/libnnstreamer_filter_nntrainer.so
549
550 %files -n nnstreamer-nntrainer-devel-static
551 %manifest nntrainer.manifest
552 %defattr(-,root,root,-)
553 %license LICENSE
554 %{_libdir}/libnnstreamer_filter_nntrainer.a
555
556 %endif #nnstreamer_filter
557 %endif #tizen
558
559 %files applications
560 %manifest nntrainer.manifest
561 %defattr(-,root,root,-)
562 %license LICENSE
563 %{_libdir}/nntrainer/bin/applications/*
564
565 %if 0%{?gcov:1}
566 %files gcov
567 %{_datadir}/gcov/obj/*
568 %endif
569
570 %if 0%{?testcoverage}
571 %files unittest-coverage
572 %{_datadir}/nntrainer/unittest/*
573 %endif
574
575 %changelog
576 * Fri Sep 24 2021 Jijoong Moon <jijoong.moon@samsung.com>
577 - Release of 0.3.0
578 * Wed Jun 02 2021 Jijoong Moon <jijoong.moon@samsung.com>
579 - Release of 0.2.0
580 * Wed Sep 23 2020 Jijoong Moon <jijoong.moon@samsung.com>
581 - Release of 0.1.1
582 * Mon Aug 10 2020 Jijoong Moon <jijoong.moon@samsung.com>
583 - Release of 0.1.0.rc1
584 * Wed Mar 18 2020 Jijoong Moon <jijoong.moon@samsung.com>
585 - packaged nntrainer