A Northstar labor pyproject.toml-ja NumPy-t és SciPy-t
ír elő. Három különböző gépen három eltérő telepítési hibát látunk,
mielőtt bármilyen elemzés elindulhatna:
ERROR: No matching distribution found for numpy==2.1.1Failed building wheel for numpy; error: command 'gcc' failed with exit code 1ImportError: libcblas.so.3: cannot open shared object file: No such file or directoryA megfigyelési egység egy telepítési kísérlet: a teljes hibakimenet, a használt Python-verzió, az operációs rendszer és a processzorarchitektúra. A cél annak eldöntése, hogy az adott hiba wheel-, rendszerkönyvtár- vagy solverprobléma-e, és hogy uv/pip vagy conda/mamba környezetet érdemes-e választani. Az ellenőrzés feltétele: a telepítés után a Python sikeresen importálja a NumPy-t, és egy kézzel ellenőrizhető mátrixszorzás a várt eredményt adja.
Induló feladat: a három üzenet közül melyikhez melyik első vizsgálati lépés tartozik – (a) Python-verzió ellenőrzése, (b) C/Fortran fordító megléte, (c) a megosztott könyvtárak dinamikus feloldása? A megoldást a fejezet végén adjuk meg.
A wheel (kerék) a Python-csomagok előre lefordított
bináris formátuma. A .whl fájlban a csomag készre fordított
kódja és metaadatai vannak; telepítéskor a csomagkezelő csak a megfelelő
helyre csomagolja ki őket. Ennek akkor van jelentősége, ha a csomag
natív, C, C++ vagy Fortran kódon alapul, és a telepítőgépen nincs
fordító vagy a szükséges rendszerfejléc.
Egy wheel-fájlnév platformcímkéi pontosan megmondják, milyen környezethez készült. Például:
numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
cp312: CPython 3.12 interpreterhez készült;manylinux_2_17_x86_64: x86-64 processzorú Linuxon
futtatható, a manylinux egy szabványosított
bináris-kompatibilitási profil;manylinux címke több régebbi és újabb
Linux-disztribúcióval való kompatibilitást jelez.Ha a wheel nem elérhető az adott platformra, a pip vagy uv
megpróbálhatja az sdist-ből (source distribution)
felépíteni a csomagot. Ez a forrásfordítás (source
build): a telepítőgépen fut le a fordító, amihez megfelelő C- és gyakran
Fortran-fordítóra, a függő rendszerkönyvtárak fejléceire és
build-eszközökre van szükség. A második hibaüzenetben szereplő
gcc az egyik ilyen fordító; ha hiányzik vagy nem
kompatibilis, a build meghiúsul.
A NumPy és a SciPy nagy része C-ben és Fortranban írt, nagy teljesítményű numerikus rutinokat hív meg. A lineáris algebrai alapműveletek szabványos felületét a BLAS (Basic Linear Algebra Subprograms) adja, amelynek három szintje van: vektor–vektor, mátrix–vektor és mátrix–mátrix műveletek. A NumPy például a mátrixszorzást általában egy külső BLAS-megvalósításra, például az OpenBLAS-ra vagy az Intel MKL-re bízza. A SciPy ehhez még a LAPACK-ot is használja, amely a lineáris egyenletrendszerek megoldására, sajátérték-számításra és hasonlókra épül.
Ennek matematikai hídja egyszerű: a mátrixszorzás mint könyvtári művelet.
Legyen és . A szorzat , ahol minden indexre
Itt az sorainak száma, a közös belső dimenzió, a oszlopainak száma. A példában dimenzió nélküli, tiszta számokkal dolgozunk; valós adatelemzésben a mértékegységet a mátrix elemeinek jelentése hordozza, ezért a szorzatnál mindig külön kell megnevezni, mit jelentenek a bemenő oszlopok.
Kis kézi kontroll:
Ekkor , és
A NumPy-ban a @ operátor ezt a BLAS-hívást takarja. A
Python-kód tehát nem maga írja meg a belső ciklusokat; a helyes működés
a telepített natív könyvtártól függ. Ha a BLAS hiányzik, rosszul linkelt
vagy nem kompatibilis az ABI-val, akkor nem az algoritmus hibás, hanem a
futtatókörnyezet.
A conda és a gyorsabb solverű mamba nemcsak
Python-csomagokat, hanem a Pythont és a natív könyvtárakat is csomagként
kezelik. Egy conda create -n labor python=3.12 numpy scipy
parancs a Python-interpretert, a NumPy-t, a SciPy-t és az általuk
igényelt BLAS/LAPACK-megvalósítást is binárisan, előre lefordítva
telepíti a környezetbe. Ezért a conda különösen akkor előnyös, ha a
PyPI-n nincs megfelelő wheel, vagy ha a rendszerfordító hiányzik.
A conda-csomagok csatornákból (channel) érkeznek. A
defaults az Anaconda által karbantartott, míg a
conda-forge közösségi csatorna, amely rendszerint frissebb
és szélesebb körű buildeket kínál. A tanulási főútban a csatornák pontos
verzióját nem kötjük meg e fejezethez; a választásnál az a kérdés, hogy
a projekt által igényelt csomagok és a Python-verzió konzisztensen
elérhetők-e.
Példa conda/mamba munkamenet (Linux/macOS, a projektgyökérből):
mamba create -n northstar python=3.12 numpy scipy -c conda-forge
mamba activate northstar
python -c "import numpy as np; print(np.__version__); print(np.show_config())"A np.show_config() kimenete szemléltető lehet; egy
lehetséges részlet:
blas_mkl_info:
NOT AVAILABLE
blas_opt_info:
libraries = ['openblas', 'openblas']
library_dirs = ['/home/user/miniforge3/envs/northstar/lib']
language = f77
Ez azt mutatja, hogy a NumPy az OpenBLAS-t használja. A tényleges kimenet gép- és verziófüggő, ezért ezt csak a saját gépen futtatva érdemes ellenőrizni.
A conda és mamba parancsok szintaxisa a mindennapi használatban nagyrészt megegyezik; a mamba gyorsabb feloldást ígér. A könyvben conda/mamba néven hivatkozunk rájuk, mert a döntési szerep azonos.
A legnagyobb telepítési csapda a pip/uv és a conda tetszőleges sorrendű keverése. Ennek oka, hogy a conda saját solverrel és saját függőségi gráfbal dolgozik, míg a pip/uv a PyPI wheeljeiből építkezik. A két rendszer nem látja egymás döntéseit.
Ellenpélda:
conda create -n mixed python=3.12 numpy
conda activate mixed
pip install scipy
conda install pandasA pip install scipy telepíthet egy olyan SciPy buildet,
amely más NumPy-ABI-ra épül, mint amit a conda telepített. Ezután a
conda install pandas a conda solver döntése alapján
kicserélheti vagy downgrade-elheti a NumPy-t, miközben a pip által
telepített SciPy ugyanott marad. Végeredmény: inkonzisztens bináris
környezet, amelyben egy import vagy egy BLAS-hívás hibát
ad. A reprodukálhatósági stratégia ezért az: egy környezetben vagy
conda/mamba, vagy uv/pip kezelje a Python-csomagokat; a kettőt ne
váltogassuk ugyanazon a környezeten.
Az alábbi három üzenet szemléltető példa, nem valós futási napló. A diagnosztikai lépések azonban konkrétak és futtathatók.
ERROR: Could not find a version that satisfies the requirement numpy==2.1.1
ERROR: No matching distribution found for numpy==2.1.1
Első vizsgálati lépés: a Python-verzió és a platform ellenőrzése:
python -V
python -c "import platform; print(platform.platform(), platform.machine())"Ha a kimenet például Python 3.13-at mutat, de a kért NumPy-kiadáshoz
csak 3.12-es wheel létezik, akkor a hiba nem a csomag hibája, hanem
verzióillesztési probléma. A megoldás vagy a Python-verzió rögzítése a
projektben (a tanulási alap CPython 3.12), vagy a NumPy-verzió
tartományának módosítása a pyproject.toml-ban.
Failed building wheel for numpy
error: command 'gcc' failed with exit code 1
Itt a telepítő nem talált kész wheel-t, ezért megpróbálta az sdist-et lefordítani, de a rendszerfordító hiányzik vagy hibás. Első vizsgálati lépés a toolchain megléte:
gcc --version
gfortran --version || echo "gfortran nincs telepítve"Ha a gfortran hiányzik, a NumPy és a SciPy
forrásfordítása a legtöbb platformon nem fog menni. Ebben az esetben
vagy a megfelelő wheel-t kell megkeresni (például Python-verzió
emelésével/süllyesztésével), vagy conda/mamba környezetre váltani, amely
binárisan hozza a csomagot és a BLAS-t.
ImportError: libcblas.so.3: cannot open shared object file: No such file or directory
Ez a hiba akkor jelentkezik, amikor a Python már elindult, de a betöltött natív modul egy megosztott C/Fortran könyvtárat keres, amely nincs a dinamikus keresési útvonalon. Első vizsgálati lépés a könyvtár-függőségek listázása Linuxon:
ldd "$(python -c 'import numpy; print(numpy.__file__)')"Vagy magának a NumPy-nak a konfigurációját nézzük:
python -c "import numpy; numpy.show_config()"Ha a libcblas hiányzik a rendszerből, a leggyakoribb ok:
a NumPy-t egy olyan wheel-ből telepítettük, amely rendszer-BLAS-t
feltételez, vagy egy másik környezetből másoltuk át. A javítás vagy a
megfelelő, önálló OpenBLAS-t tartalmazó wheel telepítése, vagy
conda/mamba használata.
| Felelősség | uv + venv | conda/mamba |
|---|---|---|
| Python-interpreter kiválasztása | A pyproject.toml-ban megadott verziót a uv letöltheti
és kezelheti; a környezet Pythonja a .venv-ben van. |
A Pythont maga a conda telepíti csomagként a környezetbe. |
| Natív könyvtárak (BLAS/LAPACK) | A PyPI-wheel-ek általában tartalmazzák az OpenBLAS-t; ha nincs wheel, forrásfordítás kell. | A conda-csatorna binárisan szállítja a BLAS-t és a csomagokat együtt. |
| Függőségrögzítés | uv.lock a Python-csomagokat pontosan rögzíti; a
rendszerkönyvtárak nem részei. |
environment.yml vagy conda-lock a
conda-csomagokat rögzíti; a rendszerkönyvtárak ugyanúgy nem. |
| Operációs rendszer függősége | Windows/macOS/Linux wheel-ek; a rendszer-C lib verziója lehet korlát. | A conda-csomagok saját előtaggal dolgoznak, így kevesebb rendszerfüggőség. |
A táblázat lényege: az uv/pip a Python-ökoszisztéma natív eszköze, és
a lockkal a Python-függőségeket rögzíti; a conda/mamba a Python mellett
a natív könyvtárakat is csomagkezelő alá vonja. A 3.2-ben tanult
uv.lock tehát a conda esetében nem ugyanaz a fogalom: a
conda-környezetben a conda-lock vagy a
environment.yml pontosítására van szükség.
Most futtassuk le a kis mátrixszorzás-kontrollt egy uv-környezetben. Az alábbi kódot nem futtattuk jelen írásban; a kimenet szemléltető, elméletileg várt érték.
import numpy as np
A = np.array([[1.0, 2.0], [3.0, 4.0]], dtype=np.float64) # shape (2, 2)
B = np.array([[5.0, 6.0], [7.0, 8.0]], dtype=np.float64) # shape (2, 2)
C = A @ B # shape (2, 2)
expected = np.array([[19.0, 22.0], [43.0, 50.0]], dtype=np.float64)
print(C)
print("shape:", C.shape, "dtype:", C.dtype)
print("allclose:", np.allclose(C, expected, rtol=1e-12, atol=1e-14))Elméletileg várt szemléltető kimenet:
[[19. 22.]
[43. 50.]]
shape: (2, 2) dtype: float64
allclose: True
Futtatás a lab projektben, Linux/macOS, a projektgyökérből:
uv sync --locked
uv run --locked --no-sync python matrix_check.pyA --locked --no-sync kombináció a 3.2-ben tanult módon
garantálja, hogy a lockolt verziókat használjuk, friss feloldás
nélkül.
A mátrixszorzás ellenőrzése három invariant teljesülését jelenti:
(2, 2).float64, ezért a kimenet is float64; vegyes
típusnál a NumPy saját promóciós szabályai szerint alakul, amit külön
ellenőrizni kell.== művelettel.Ha a fenti ellenőrzések teljesülnek, a NumPy BLAS-hívása működőképes.
Ha allclose hamisat ad, akkor nem feltétlenül a BLAS hibás:
először a saját expected mátrixunkat kell ellenőrizni, majd
a dtype-ot és a shape-eket.
Numerikus bináris kompatibilitás. A Python-verzió önmagában nem írja le a numerikus stack futtatókörnyezetét. A wheel/conda csomagoknak CPU-architektúrához, rendszerkönyvtárhoz és adott esetben BLAS- vagy GPU-runtime-hoz is illeszkedniük kell. A csomag telepítése és egy egyszerű numerikus művelet sikeres lefutása két külön ellenőrzési pont.
A BLAS-szálak száma befolyásolhatja a teljesítményt és a
reprodukálható időmérést; ezért benchmarknál a szálkeretet (például
OPENBLAS_NUM_THREADS) és a platformot dokumentálni kell. Ne
sugalljuk, hogy a conda minden bináris problémára automatikusan jobb
megoldás: ez konkrét platform- és csomagfüggő döntés.
Értelmezés. A wheel-fájl neve
numpy-2.1.1-cp312-cp312-win_amd64.whl. Telepíthető-e ez
CPython 3.13-ra Linux x86-64 gépen? Indokolj a fájlnév címkéi
alapján.
Megvalósítás. Írj egy rövid Python-szkriptet,
amely kiírja, hogy a NumPy milyen BLAS/LAPACK-at talál
(numpy.show_config()), majd végez el egy
-es
mátrix és egy
-es
mátrix szorzását. Add meg a várt eredmény shape-jét, és kézzel számold
ki az eredmény első sorát, ha az első mátrix sorai rendre
,
,
,
a második mátrix oszlopai pedig
,
,
,
.
Hibakeresés. Egy gépen az
uv sync --locked sikeres, de az import numpy
ezt adja:
ImportError: /lib/x86_64-linux-gnu/libm.so.6: version GLIBC_2.28 not found.
Milyen típusú problémáról van szó? Milyen következő lépést javasolsz, és
miért nem a uv lockfájl hibája?
Megváltozott feltétel. A telepítőgépen nincs internet-hozzáférés a futtatáskor, viszont a csomagokat előre be kell csomagolni. Hogyan változik a döntés uv és conda/mamba között? Adj egy konkrét, offline munkamenet-vázlatot, és jelöld meg, mi az, ami mindkét úton kívül marad.
Nem telepíthető. A cp312 címke
CPython 3.12-höz kötött, a win_amd64 pedig 64 bites
Windowsra. CPython 3.13 Linux x86-64-hez más wheel, például
cp313-cp313-manylinux...x86_64.whl kellene. Ha ilyen nem
létezik a kért verzióhoz, akkor vagy Python-verziót kell igazítani, vagy
forrást fordítani, vagy conda/mamba csatornán keresni binárist. Ez a
válasz a címkék pontos olvasását ellenőrzi.
Várható shape: . Az első sor kiszámítása: az első sora . A szorzat első sora:
Tehát a várt első sor
.
A szkriptben az A @ B kimenet shape-jét
(3, 4)-ként ellenőrizzük. Általánosan: ha
shape-je
és
shape-je
,
akkor a belső
megegyezik, a kimenet pedig
.
A BLAS-konfiguráció kiírása a numpy.show_config()
függvénnyel történik; annak tartalma gépenként eltér, ezért itt csak az
ellenőrzés módját adjuk meg, konkrét kimenetet nem garantálunk.
A GLIBC-verzió probléma. A hiba azt jelenti,
hogy a NumPy wheel egy olyan Linux-disztribúcióra készült, amely újabb
glibc-t feltételez, mint ami a gépen van. Ez
rendszerkönyvtár-kompatibilitási probléma, nem solverprobléma. Az
uv.lock a Python-csomagok verzióját rögzíti; a wheel
platformkompatibilitása a manylinux címke szintjén múlik. A
következő lépés: olyan régebbi manylinux-wheelű NumPy-verziót
választani, amely a régebbi glibc-vel is működik, vagy conda/mamba-ra
váltani, mert a conda-csomagok saját előtaggal, a rendszer glibc-jétől
függetlenebbül telepíthetők.
Offline megoldás. Mindkét úthoz elő kell
készíteni a letöltéseket egy internetes gépen. Uv/pip esetén a
wheel-eket töltsük le egy könyvtárba (pip download vagy
uv pip download, itt a parancs neve verziófüggő lehet,
ezért a konkrét hívás előtt a helyi uv --help
ellenőrzendő), majd a célgépen ebből telepítsünk. Conda/mamba esetén a
conda pack vagy egy helyi csatorna-mirror használható. Ami
mindkét úton kívül marad: a rendszer szintű C könyvtárak (például a
glibc) és az operációs rendszer frissítései; ezeket a csomagkezelő egyik
eszköz sem viszi magával, ezért offline ismert, azonos OS-t kell
feltételezni. A lock mindkét esetben csak a saját csomagkörére
vonatkozik.
A leggyakoribb tévedés az, hogy a pip és a conda keverése
„rugalmasság”, pedig nem reprodukálhatósági stratégia. Ellenpélda: egy
csapattag conda-val telepíti a NumPy-t, majd
pip-pel telepíti a projektet, mert a
pyproject.toml-ból szeretne dolgozni. A pip wheel-je
felülírja a conda által telepített NumPy egyes fájljait, más
conda-csomagok (SciPy, statsmodels) viszont az eredeti conda-verzióhoz
lettek lefordítva. Egy mátrixszorzás még lehet, hogy fut, de egy ritkább
SciPy-művelet undefined symbol hibát dob. A környezet
reprodukálhatatlan, mert a konkrét felülírási sorrend nem dokumentált. A
helyes stratégia: egy környezet = egy csomagkezelő, és ezt a 2.3-ben
tanult Git-konfigurációban, a README-ben rögzítjük.
Önellenőrzés. A 3.2 lockolt függőségei most már
kiegészültek a bináris kérdéssel: a uv.lock a
Python-csomagok pontos verzióját adja, de nem tartalmazza a BLAS bináris
tartalmát. Ha egy másik gépen nem ugyanaz a rendszer glibc-je, a lock
önmagában nem garantál futást. Ezért a reprodukálhatósági nyilatkozatban
külön kell nevezni a Python-csomag-zárat, a natív könyvtárakat és az
operációs rendszert.
A wheel előre lefordított bináris, a forrásfordítás pedig fordítóeszközt igényel a gépen. A NumPy és SciPy BLAS/LAPACK könyvtárakat hív, ezért a mátrixművelet nem pusztán Python-számítás, hanem natív futtatókörnyezet. A conda/mamba a Pythont és a natív könyvtárakat is csomagkezelő alá vonja, a csatorna határozza meg a bináris forrást. Az uv/pip és a conda keverése inkonzisztens ABI-hoz vezet, ezért egy környezetben egy csomagkezelő működjön. A következő alfejezetben a Jupyter-kernel regisztrációját vizsgáljuk: ott az interpreter, a csomagkészlet és a notebook futásidejének összerendelése kerül középpontba.