AI-прогнозирование уловов рыбы
Прогнозирование рыбных запасов и уловов — задача на пересечении физической океанографии, экологии и ML. Рыболовные компании, управляющие органы (Росрыболовство, ВНИРО) и аквафермеры используют прогнозы для планирования промысла, квот и логистики. ML улучшает точность прогнозов по сравнению с традиционными популяционными моделями на 15-30%.
Факторы, определяющие уловы
Океанографические:
oceanographic_features = {
'sst': 'Sea Surface Temperature — влияет на распределение рыбы',
'chl_a': 'Хлорофилл-а — продуктивность экосистемы (спутниковые данные)',
'ssh': 'Sea Surface Height — течения, апвеллинг',
'mld': 'Mixed Layer Depth — термоклин (зона концентрации планктона)',
'current_u_v': 'скорость и направление течений',
'salinity': 'солёность на глубинах 0-200м',
'amo_pdo': 'Atlantic/Pacific Multidecadal Oscillation — долгосрочные циклы',
'enso': 'El Niño/La Niña — межгодовые флуктуации'
}
Биологические:
- Размерно-возрастная структура популяции
- Нерестовый сезон и успешность воспроизводства
- Кормовая база: биомасса зоопланктона, кормовой рыбы (мойва, сельдь для трески)
Промысловые:
- Усилие (Effort): количество судо-суток, тип орудий лова
- CPUE (Catch Per Unit Effort): стандартизованный индикатор запасов
Модели оценки запасов
VPA (Virtual Population Analysis): Классический метод: из данных об уловах по возрастным группам реконструировать численность популяции:
def virtual_population_analysis(catch_at_age, natural_mortality):
"""
N(a+1,y+1) = N(a,y) - C(a,y) - M(a,y)
N = численность, C = вылов, M = естественная смертность
Ретроспективный расчёт от самых старых особей назад
"""
cohort_sizes = {}
for age in range(max_age, min_age, -1):
surviving = catch_at_age[age] / (1 - np.exp(-natural_mortality))
cohort_sizes[age] = surviving
return cohort_sizes
Stock-Recruitment модели: Зависимость численности нового поколения от нерестового запаса:
def beverton_holt(spawning_stock_biomass, alpha, beta):
"""Beverton-Holt: R = alpha × SSB / (beta + SSB)"""
return alpha * spawning_stock_biomass / (beta + spawning_stock_biomass)
def ricker(spawning_stock_biomass, alpha, beta):
"""Ricker: R = alpha × SSB × exp(-beta × SSB)"""
return alpha * spawning_stock_biomass * np.exp(-beta * spawning_stock_biomass)
ML для прогнозирования
Краткосрочный прогноз уловов (1-3 месяца):
import lightgbm as lgb
def build_catch_forecast_model(historical_data, horizon_months=3):
"""
Таргет: улов в тоннах на промысловый район
Фичи: oceanographic + lagged catches + effort
"""
features = create_features(historical_data)
# Важно: временное разделение train/test
# No data leakage: обучение на < года T, тест на > T
cutoff = int(len(features) * 0.8)
X_train, X_test = features[:cutoff], features[cutoff:]
y_train, y_test = catch_series[:cutoff], catch_series[cutoff:]
model = lgb.LGBMRegressor(
n_estimators=300,
learning_rate=0.05,
num_leaves=31
)
model.fit(X_train, np.log1p(y_train)) # log-трансформация для скewed distribution
return model
catch_features = {
'catch_lag_1': catch.shift(1),
'catch_lag_12': catch.shift(12), # год назад (сезонность)
'sst_lag_2': sst.shift(2), # 2-месячный лаг влияния SST
'chl_a_lag_3': chl_a.shift(3), # 3-месячный лаг продуктивности
'enso_oni': enso_oni_index,
'fishing_effort': effort,
'month': catch.index.month,
'year': catch.index.year
}
Spatial ML — прогноз по промысловым районам:
# Для каждого промыслового квадрата (0.5° × 0.5°)
# Отдельная модель или глобальная с spatial features
spatial_features = {
'lat': grid_lat,
'lon': grid_lon,
'sst': satellite_sst[lat, lon],
'chl': satellite_chl[lat, lon],
'depth': bathymetry[lat, lon],
'distance_to_shelf': shelf_distance[lat, lon],
'eddy_activity': sea_level_anomaly_std[lat, lon]
}
Deep Learning для пространственно-временных данных:
import torch.nn as nn
class FishingGroundPredictor(nn.Module):
"""
ConvLSTM: пространственно-временное прогнозирование
Входные карты: SST, Chl-a, SSH → 2D grid
Выходные карты: вероятность высокого улова по квадратам
"""
def __init__(self, input_channels=3, hidden_size=64, output_channels=1):
super().__init__()
self.convlstm = ConvLSTM(input_channels, hidden_size, kernel_size=3, n_layers=2)
self.conv_out = nn.Conv2d(hidden_size, output_channels, kernel_size=1)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
lstm_out, _ = self.convlstm(x)
return self.sigmoid(self.conv_out(lstm_out))
Данные и интеграция
Спутниковые данные:
- NASA MODIS, Copernicus Marine Service (CMEMS): SST, Chl-a, SSH — ежедневные глобальные продукты
- NOAA CoastWatch: Pacific/Atlantic региональные продукты
- Argo floats: профили температуры и солёности на глубинах
Промысловая статистика:
- Рапортные данные судов (судовые суточные донесения, ССД): ICES, FAO
- VMS (Vessel Monitoring System): GPS-трекинг промысловых судов → где ловят
- Электронные промысловые журналы (ЭПЖ): Росрыболовство ЦСМС
Обработка спутниковых данных:
import xarray as xr
import numpy as np
# CMEMS данные в NetCDF формате
ds = xr.open_dataset('cmems_sst_2024.nc')
sst_region = ds['thetao'].sel(
lat=slice(55, 75), # Баренцево море
lon=slice(10, 60),
depth=0
)
# Ежемесячные аномалии (клайматология)
climatology = sst_region.groupby('time.month').mean()
sst_anomaly = sst_region.groupby('time.month') - climatology
Управление квотами и промыслом
Оперативный анализ: Прогноз на промысловый сезон → распределение квоты по районам и периодам. Обновление прогноза ежемесячно по мере поступления новых oceanographic данных.
Оптимальное время промысла: Для пелагических видов (скумбрия, сельдь) — прогноз концентрации рыбы по квадратам. Рекомендация капитану: районы с высоким ожидаемым CPUE.
Влияние изменения климата: Долгосрочные прогнозы (10-30 лет) на основе климатических сценариев CMIP6: смещение нерестилищ, изменение продуктивности отдельных районов. Научное применение для стратегического управления запасами.
Сроки: интеграция CMEMS данных + базовая модель CPUE + промысловая статистика — 4-5 недель. ConvLSTM пространственный прогноз + stock-recruitment модель + spatio-temporal dashboard + ЭПЖ интеграция — 3-4 месяца.







