-
Notifications
You must be signed in to change notification settings - Fork 151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Invoking LightGBM via JEP has distinct behaviour than invoking outside of JEP (simple python script) #205
Comments
Linked with the following issue: microsoft/LightGBM#2500 |
Is there a chance you could test with Jep 3.9 and the |
Thanks for including a full repeatable test case. I downloaded your model and copied your code for classifier.py and TestLightGBM.java and I was able to run it successfully. Unfortunately I did not see the same output as you from java, the scores I got from java/Jep match what you got from Python. I suspect there must be something different in your environment that is causing your problems. For reference, I am also on Ubuntu 18.04 and my python is 3.6.7. I first tried jep 3.9.0 with OpenJDK 11 and when that didn't produce the error I tried jep 3.7.1 with OpenJDK 8. I just used pip to install lightgbm and I am getting version 2.3.0. Initially I commented out the pandas import in classifier.py since I didn't have pandas, but I even installed pandas and added the import back and it still works for me. Since I cannot repeat the problem I can only speculate on what might be causing it. My best guess is that there is something on your Java classpath that is interfering with the python imports used by lightgbm. Jep looks at everything in your classpath when processing a python import and we have run into issues before where a java package will override a python package with the same name and cause problems in python. In my test the only two things on my classpath were the jep jar and the directory with the TestLightGBM.class. You didn't mention your exact classpath so it is possible yours is more complicated, if you trim it down and it fixes the problems that would help isolate the problem. |
Thank you for your answers. This was the test I did with jep version 3.7.1, in the Jep console :
|
@bsteffensmeier , just to give you some feedback on this matter: I have created a docker container with ubuntu 18.04 , plus all the libs I listed above, and it **worked as expected inside the docker container ** . I really am at a loss with this, because I don't know what else to validate. Any ideas on this? @ndjensen and @bsteffensmeier ? |
I would just try validating all your assumptions about what is loaded. I think the multiple python versions has potential for problems but it looks like you have everything configured for that to not matter. I recommend going through your test on the jep console and then validating every package involved loads from where you think it should, something like this:
You could also check the loaded libraries from another terminal with the pid, something like I don't know anything about lightgbm so this might not make sense, but the fact you don't get errors but get the same answer every time makes me think there is something wrong with the model. Is there any chance it got truncated or somehow simplified? If you have any way to get more information about the model then you might try to investigate into it and see if that is different. I'm just thinking maybe the problem is more with the model loading rather than the actual model execution, although I don't know that the distinction gets you any closer to a solution. |
@bsteffensmeier that last part about the model loading was a correct assumption! |
@bsteffensmeier found the problem.
If I change the default value to C, or US, it works as expected. I don't know if this qualifies as a JEP bug, but it certainly seems so. Thank you for all your help. |
Excellent, thanks for getting back to us with the answer. It looks like Jep is interpreting your locale from your environment while your Python is ignoring it. It feels like it is more correct to respect your environment. We generally try to match Python though so if we can figure out why Python is doing what it is then we could consider emulating it or providing some mechanism to override it. I suspect that python itself is not ignoring the environment but perhaps something in conda is reseting it. If you try the test with the system python and the Portuguese local does it read the model correctly or do you get constant results? I'd also be curious about what the locale module reports when it is working correctly. The documentation for that module mentions embedded applications but it seems to be focused on disabling it and I don't think that would help you. |
I tried it on my system and even on the default system Python it works correctly when your environment is Portuguese, it turns out Python always uses the default 'C' locale regardless of your environment. Interestingly if you try to actually use a locale in your Python then lightgbm will break, like this:
This could be considered a bug in lightgbm, I would expect a file format to be portable and to work regardless of a users locale settings. You can also use the locale module to fix jep:
I am still unsure what, if anything, should change within jep. We could set the locale during initialization but I've noticed slight differences in locale.getlocale() between the default Python and a manually configured jep. I also found PEP 587, which gives us the ability to set the locale with the exact code python uses. We need to look closer at that pep in general since other options may be worth using or exposing to Java users but I would prefer to wait until we drop support for every Python version before 3.8 so we don't have to figure out how to handle options without PEP 587. I am hesitant to make any changes to the current behaviour because the locale settings affect the entire application and could have side affects in the JVM or other JNI libraries. It seems rude for an embedded library to be changing process wide settings. It appears the reason Python isn't automatically making locale changes is because their developers feel that is bad behaviour for a library, From Python Issue 24589:
For now my recommendation would be that any application using jep that is sensitive to the locale should be calling locale.setlocale() which will ensure consistent behaviour in both Python and jep. |
Hello @ManuelMourato25, @bsteffensmeier, the issue is fixed now, locale no longer impacts the model read/write process by design in the core implementation. Check
Can you close this? :) |
When Java is used, the default C++ locale is broken. This is true for Java providers that use the C API or even Python models that require JEP. This patch solves that issue making the model reads/writes insensitive to such settings. To achieve it, within the model read/write codebase: - C++ streams are imbued with the classic locale - Calls to functions that are dependent on the locale are replaced - The default locale is not changed! This approach means: - The user's locale is never tampered with, avoiding issues such as microsoft#2979 with the previous approach microsoft#2891 - Datasets can still be read according the user's locale - The model file has a single format independent of locale Changes: - Add CommonC namespace which provides faster locale-independent versions of Common's methods - Model code makes conversions through CommonC - Cleanup unused Common methods - Performance improvements. Use fast libraries for locale-agnostic conversion: - value->string: https://github.com/fmtlib/fmt - string->double: https://github.com/lemire/fast_double_parser (10x faster double parsing according to their benchmark) Bugfixes: - microsoft#2500 - microsoft#2890 - ninia/jep#205 (as it is related to LGBM as well)
When Java is used, the default C++ locale is broken. This is true for Java providers that use the C API or even Python models that require JEP. This patch solves that issue making the model reads/writes insensitive to such settings. To achieve it, within the model read/write codebase: - C++ streams are imbued with the classic locale - Calls to functions that are dependent on the locale are replaced - The default locale is not changed! This approach means: - The user's locale is never tampered with, avoiding issues such as microsoft#2979 with the previous approach microsoft#2891 - Datasets can still be read according the user's locale - The model file has a single format independent of locale Changes: - Add CommonC namespace which provides faster locale-independent versions of Common's methods - Model code makes conversions through CommonC - Cleanup unused Common methods - Performance improvements. Use fast libraries for locale-agnostic conversion: - value->string: https://github.com/fmtlib/fmt - string->double: https://github.com/lemire/fast_double_parser (10x faster double parsing according to their benchmark) Bugfixes: - microsoft#2500 - microsoft#2890 - ninia/jep#205 (as it is related to LGBM as well)
When Java is used, the default C++ locale is broken. This is true for Java providers that use the C API or even Python models that require JEP. This patch solves that issue making the model reads/writes insensitive to such settings. To achieve it, within the model read/write codebase: - C++ streams are imbued with the classic locale - Calls to functions that are dependent on the locale are replaced - The default locale is not changed! This approach means: - The user's locale is never tampered with, avoiding issues such as microsoft#2979 with the previous approach microsoft#2891 - Datasets can still be read according the user's locale - The model file has a single format independent of locale Changes: - Add CommonC namespace which provides faster locale-independent versions of Common's methods - Model code makes conversions through CommonC - Cleanup unused Common methods - Performance improvements. Use fast libraries for locale-agnostic conversion: - value->string: https://github.com/fmtlib/fmt - string->double: https://github.com/lemire/fast_double_parser (10x faster double parsing according to their benchmark) Bugfixes: - microsoft#2500 - microsoft#2890 - ninia/jep#205 (as it is related to LGBM as well)
When Java is used, the default C++ locale is broken. This is true for Java providers that use the C API or even Python models that require JEP. This patch solves that issue making the model reads/writes insensitive to such settings. To achieve it, within the model read/write codebase: - C++ streams are imbued with the classic locale - Calls to functions that are dependent on the locale are replaced - The default locale is not changed! This approach means: - The user's locale is never tampered with, avoiding issues such as microsoft#2979 with the previous approach microsoft#2891 - Datasets can still be read according the user's locale - The model file has a single format independent of locale Changes: - Add CommonC namespace which provides faster locale-independent versions of Common's methods - Model code makes conversions through CommonC - Cleanup unused Common methods - Performance improvements. Use fast libraries for locale-agnostic conversion: - value->string: https://github.com/fmtlib/fmt - string->double: https://github.com/lemire/fast_double_parser (10x faster double parsing according to their benchmark) Bugfixes: - microsoft#2500 - microsoft#2890 - ninia/jep#205 (as it is related to LGBM as well)
When Java is used, the default C++ locale is broken. This is true for Java providers that use the C API or even Python models that require JEP. This patch solves that issue making the model reads/writes insensitive to such settings. To achieve it, within the model read/write codebase: - C++ streams are imbued with the classic locale - Calls to functions that are dependent on the locale are replaced - The default locale is not changed! This approach means: - The user's locale is never tampered with, avoiding issues such as microsoft#2979 with the previous approach microsoft#2891 - Datasets can still be read according the user's locale - The model file has a single format independent of locale Changes: - Add CommonC namespace which provides faster locale-independent versions of Common's methods - Model code makes conversions through CommonC - Cleanup unused Common methods - Performance improvements. Use fast libraries for locale-agnostic conversion: - value->string: https://github.com/fmtlib/fmt - string->double: https://github.com/lemire/fast_double_parser (10x faster double parsing according to their benchmark) Bugfixes: - microsoft#2500 - microsoft#2890 - ninia/jep#205 (as it is related to LGBM as well)
When Java is used, the default C++ locale is broken. This is true for Java providers that use the C API or even Python models that require JEP. This patch solves that issue making the model reads/writes insensitive to such settings. To achieve it, within the model read/write codebase: - C++ streams are imbued with the classic locale - Calls to functions that are dependent on the locale are replaced - The default locale is not changed! This approach means: - The user's locale is never tampered with, avoiding issues such as microsoft#2979 with the previous approach microsoft#2891 - Datasets can still be read according the user's locale - The model file has a single format independent of locale Changes: - Add CommonC namespace which provides faster locale-independent versions of Common's methods - Model code makes conversions through CommonC - Cleanup unused Common methods - Performance improvements. Use fast libraries for locale-agnostic conversion: - value->string: https://github.com/fmtlib/fmt - string->double: https://github.com/lemire/fast_double_parser (10x faster double parsing according to their benchmark) Bugfixes: - microsoft#2500 - microsoft#2890 - ninia/jep#205 (as it is related to LGBM as well)
* Fix LightGBM models locale sensitivity and improve R/W performance. When Java is used, the default C++ locale is broken. This is true for Java providers that use the C API or even Python models that require JEP. This patch solves that issue making the model reads/writes insensitive to such settings. To achieve it, within the model read/write codebase: - C++ streams are imbued with the classic locale - Calls to functions that are dependent on the locale are replaced - The default locale is not changed! This approach means: - The user's locale is never tampered with, avoiding issues such as #2979 with the previous approach #2891 - Datasets can still be read according the user's locale - The model file has a single format independent of locale Changes: - Add CommonC namespace which provides faster locale-independent versions of Common's methods - Model code makes conversions through CommonC - Cleanup unused Common methods - Performance improvements. Use fast libraries for locale-agnostic conversion: - value->string: https://github.com/fmtlib/fmt - string->double: https://github.com/lemire/fast_double_parser (10x faster double parsing according to their benchmark) Bugfixes: - #2500 - #2890 - ninia/jep#205 (as it is related to LGBM as well) * Align CommonC namespace * Add new external_libs/ to python setup * Try fast_double_parser fix #1 Testing commit e09e5aad828bcb16bea7ed0ed8322e019112fdbe If it works it should fix more LGBM builds * CMake: Attempt to link fmt without explicit PUBLIC tag * Exclude external_libs from linting * Add exernal_libs to MANIFEST.in * Set dynamic linking option for fmt. * linting issues * Try to fix lint includes * Try to pass fPIC with static fmt lib * Try CMake P_I_C option with fmt library * [R-package] Add CMake support for R and CRAN * Cleanup CMakeLists * Try fmt hack to remove stdout * Switch to header-only mode * Add PRIVATE argument to target_link_libraries * use fmt in header-only mode * Remove CMakeLists comment * Change OpenMP to PUBLIC linking in Mac * Update fmt submodule to 7.1.2 * Use fmt in header-only-mode * Remove fmt from CMakeLists.txt * Upgrade fast_double_parser to v0.2.0 * Revert "Add PRIVATE argument to target_link_libraries" This reverts commit 3dd45dd. * Address James Lamb's comments * Update R-package/.Rbuildignore Co-authored-by: James Lamb <jaylamb20@gmail.com> * Upgrade to fast_double_parser v0.3.0 - Solaris support * Use legacy code only in Solaris * Fix lint issues * Fix comment * Address StrikerRUS's comments (solaris ifdef). * Change header guards Co-authored-by: James Lamb <jaylamb20@gmail.com>
Describe the bug
I am trying to call a LightGBM model (https://github.com/microsoft/LightGBM) via JEP, in order to predict the scores of a couple of records.
However, if I execute the Booster.predict command via JEP, it returns a constant score of 0.04742587, for every distinct record passed.
The same does not happen if I invoke LGBM from a Python script.
Any ideas on what the issue might be?
Note: when using JEP to invoke different models, like xgboost, this issue does not happen.
To Reproduce
COMMON STEPS:
Extract the following model inside the zip into a file named m0_test.model:
m0_test.zip
Save the following script as classifier.py, in any folder you wish (replace <PATH_TO_MODEL> accordingly)
JEP EXECUTION:
See that the return score is always constant independent of the record classified:
PYTHON EXECUTION:
Environment (please complete the following information):
The text was updated successfully, but these errors were encountered: