{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from PIL import Image\nimport numpy as np\nfrom pathlib import Path\n\nsize = (500, 250)\nimg_p = '/kaggle/input/csiro-biomass/train/ID1012260530.jpg'\nimg = np.array(Image.open(img_p))\nimg_resized = np.array(Image.open(img_p).resize(size, Image.Resampling.LANCZOS))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:55.243007Z","iopub.execute_input":"2025-12-01T15:10:55.243187Z","iopub.status.idle":"2025-12-01T15:10:55.526961Z","shell.execute_reply.started":"2025-12-01T15:10:55.243170Z","shell.execute_reply":"2025-12-01T15:10:55.526147Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.imshow(img)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:55.528703Z","iopub.execute_input":"2025-12-01T15:10:55.528926Z","iopub.status.idle":"2025-12-01T15:10:56.036992Z","shell.execute_reply.started":"2025-12-01T15:10:55.528908Z","shell.execute_reply":"2025-12-01T15:10:56.036239Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.imshow(img_resized)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:56.037775Z","iopub.execute_input":"2025-12-01T15:10:56.038027Z","iopub.status.idle":"2025-12-01T15:10:56.234320Z","shell.execute_reply.started":"2025-12-01T15:10:56.038005Z","shell.execute_reply":"2025-12-01T15:10:56.233574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndf_train = pd.read_csv('/kaggle/input/csiro-biomass/train.csv')\ndf_train.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:56.235109Z","iopub.execute_input":"2025-12-01T15:10:56.235429Z","iopub.status.idle":"2025-12-01T15:10:57.916631Z","shell.execute_reply.started":"2025-12-01T15:10:56.235405Z","shell.execute_reply":"2025-12-01T15:10:57.915990Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train['Month'] = df_train['Sampling_Date'].apply(lambda date: date.split('/')[1])\ndf_train['Month'].unique()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:57.917426Z","iopub.execute_input":"2025-12-01T15:10:57.918077Z","iopub.status.idle":"2025-12-01T15:10:57.926791Z","shell.execute_reply.started":"2025-12-01T15:10:57.918057Z","shell.execute_reply":"2025-12-01T15:10:57.925994Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train.drop(['Sampling_Date', 'sample_id'], axis=1, inplace=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:57.927691Z","iopub.execute_input":"2025-12-01T15:10:57.927960Z","iopub.status.idle":"2025-12-01T15:10:57.957193Z","shell.execute_reply.started":"2025-12-01T15:10:57.927934Z","shell.execute_reply":"2025-12-01T15:10:57.956438Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = df_train.drop('target', axis=1)\ny = df_train['target']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:57.959461Z","iopub.execute_input":"2025-12-01T15:10:57.959682Z","iopub.status.idle":"2025-12-01T15:10:57.974512Z","shell.execute_reply.started":"2025-12-01T15:10:57.959666Z","shell.execute_reply":"2025-12-01T15:10:57.973609Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:57.975503Z","iopub.execute_input":"2025-12-01T15:10:57.975988Z","iopub.status.idle":"2025-12-01T15:10:58.006734Z","shell.execute_reply.started":"2025-12-01T15:10:57.975970Z","shell.execute_reply":"2025-12-01T15:10:58.006062Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images_to_rows = []\n\nfor img_path in X['image_path']:\n    img = np.array(Image.open(f'/kaggle/input/csiro-biomass/{img_path}').convert('RGB').resize(size,\n                                                                Image.Resampling.LANCZOS))\n    images_to_rows.append(img)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:10:58.007457Z","iopub.execute_input":"2025-12-01T15:10:58.007709Z","iopub.status.idle":"2025-12-01T15:13:19.187749Z","shell.execute_reply.started":"2025-12-01T15:10:58.007688Z","shell.execute_reply":"2025-12-01T15:13:19.187115Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images_to_rows = np.array(images_to_rows) / 255\nimages_to_rows.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:19.188512Z","iopub.execute_input":"2025-12-01T15:13:19.188788Z","iopub.status.idle":"2025-12-01T15:13:21.064727Z","shell.execute_reply.started":"2025-12-01T15:13:19.188759Z","shell.execute_reply":"2025-12-01T15:13:21.063997Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import keras as kr\n\n#tpu = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='local')\n#tf.tpu.experimental.initialize_tpu_system(tpu)\n#tpu_strategy = tf.distribute.TPUStrategy(tpu)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:21.065542Z","iopub.execute_input":"2025-12-01T15:13:21.065841Z","iopub.status.idle":"2025-12-01T15:13:35.679847Z","shell.execute_reply.started":"2025-12-01T15:13:21.065818Z","shell.execute_reply":"2025-12-01T15:13:35.679038Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"conv_base = kr.applications.VGG16(\n    weights='imagenet',\n    include_top=False,\n    input_shape=(250, 500, 3)\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:35.680730Z","iopub.execute_input":"2025-12-01T15:13:35.681732Z","iopub.status.idle":"2025-12-01T15:13:40.385049Z","shell.execute_reply.started":"2025-12-01T15:13:35.681702Z","shell.execute_reply":"2025-12-01T15:13:40.384334Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"conv_base.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:40.385780Z","iopub.execute_input":"2025-12-01T15:13:40.385974Z","iopub.status.idle":"2025-12-01T15:13:40.411217Z","shell.execute_reply.started":"2025-12-01T15:13:40.385959Z","shell.execute_reply":"2025-12-01T15:13:40.410678Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\nle_state = LabelEncoder()\nle_species = LabelEncoder()\nle_target_name = LabelEncoder()\nX['State'] = le_state.fit_transform(X['State'])\nX['Species'] = le_species.fit_transform(X['Species'])\nX['target_name'] = le_target_name.fit_transform(X['target_name'])\nX.drop('image_path', axis=1, inplace=True)\nX.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:40.411968Z","iopub.execute_input":"2025-12-01T15:13:40.412288Z","iopub.status.idle":"2025-12-01T15:13:40.452042Z","shell.execute_reply.started":"2025-12-01T15:13:40.412267Z","shell.execute_reply":"2025-12-01T15:13:40.451451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X['Month'] = X['Month'].apply(lambda x: int(x))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:40.452736Z","iopub.execute_input":"2025-12-01T15:13:40.452985Z","iopub.status.idle":"2025-12-01T15:13:40.457654Z","shell.execute_reply.started":"2025-12-01T15:13:40.452964Z","shell.execute_reply":"2025-12-01T15:13:40.456858Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X.hist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:40.458341Z","iopub.execute_input":"2025-12-01T15:13:40.458567Z","iopub.status.idle":"2025-12-01T15:13:41.351254Z","shell.execute_reply.started":"2025-12-01T15:13:40.458544Z","shell.execute_reply":"2025-12-01T15:13:41.350670Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X.describe()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:41.351957Z","iopub.execute_input":"2025-12-01T15:13:41.352251Z","iopub.status.idle":"2025-12-01T15:13:41.373986Z","shell.execute_reply.started":"2025-12-01T15:13:41.352223Z","shell.execute_reply":"2025-12-01T15:13:41.373235Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import StandardScaler\n\nX['target_name'] /= 4\nX['Month'] /= 12\nX['Species'] /= 14\nX['State'] /= 3\nX[['Height_Ave_cm']] = StandardScaler().fit_transform(X[['Height_Ave_cm']])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:41.374724Z","iopub.execute_input":"2025-12-01T15:13:41.374902Z","iopub.status.idle":"2025-12-01T15:13:41.383350Z","shell.execute_reply.started":"2025-12-01T15:13:41.374888Z","shell.execute_reply":"2025-12-01T15:13:41.382779Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X.describe()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:41.384007Z","iopub.execute_input":"2025-12-01T15:13:41.384199Z","iopub.status.idle":"2025-12-01T15:13:41.414234Z","shell.execute_reply.started":"2025-12-01T15:13:41.384184Z","shell.execute_reply":"2025-12-01T15:13:41.413676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X.hist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:41.414890Z","iopub.execute_input":"2025-12-01T15:13:41.415427Z","iopub.status.idle":"2025-12-01T15:13:42.140545Z","shell.execute_reply.started":"2025-12-01T15:13:41.415410Z","shell.execute_reply":"2025-12-01T15:13:42.139792Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_img_train, X_img_val, X_num_train, X_num_val, y_train, y_val = train_test_split(\n    images_to_rows, X, y, test_size=0.2, random_state=42,\n    stratify=X['Species']\n)\n\n# use control data 1 time\nX_img_val, X_img_control, X_num_val, X_num_control, y_val, y_control = train_test_split(\n    X_img_val, X_num_val, y_val, test_size=0.2, random_state=42\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:42.141740Z","iopub.execute_input":"2025-12-01T15:13:42.142108Z","iopub.status.idle":"2025-12-01T15:13:44.080872Z","shell.execute_reply.started":"2025-12-01T15:13:42.142083Z","shell.execute_reply":"2025-12-01T15:13:44.079935Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_multimodal_model(img_shape=(250, 500, 3), num_features=7):\n    # Вход для изображений\n    img_input = kr.layers.Input(shape=img_shape, name='image_input')\n    \n    conv_base.trainable = False  # замораживаем веса если нужно\n    \n    # Обработка изображений\n    x_img = conv_base(img_input)\n    x_img = kr.layers.GlobalAveragePooling2D()(x_img)\n    x_img = kr.layers.Dense(512, activation='relu')(x_img)\n    #x_img = layers.Dropout(0.3)(x_img)\n    \n    # Вход для числовых данных\n    num_input = kr.layers.Input(shape=(num_features,), name='numeric_input')\n    \n    # Обработка числовых данных\n    x_num = kr.layers.Dense(512, activation='relu')(num_input)\n    x_num = kr.layers.Dropout(0.5)(x_num)\n    x_num = kr.layers.Dense(256, activation='relu')(x_num)\n    \n    # Объединение двух ветвей\n    combined = kr.layers.concatenate([x_img, x_num])\n    \n    # Общая часть\n    x = kr.layers.Dense(512, activation='relu')(combined)\n    x = kr.layers.Dropout(0.5)(x)\n    x = kr.layers.Dense(256, activation='relu')(x)\n    \n    # Выходной слой (зависит от задачи)\n    # Для бинарной классификации:\n    output = kr.layers.Dense(1, name='output')(x)\n    # Для многоклассовой классификации:\n    # output = layers.Dense(num_classes, activation='softmax', name='output')(x)\n    # Для регрессии:\n    # output = layers.Dense(1, activation='linear', name='output')(x)\n    \n    # Создаем модель\n    model = kr.Model(inputs=[img_input, num_input], outputs=output)\n    \n    return model\n\n# Создание модели\n#img_shape = (224, 224, 3)  # пример размера изображения\nnum_features = X.shape[1]  # количество числовых признаков\n\nmodel = create_multimodal_model(num_features=num_features)\nmodel.compile(\n    optimizer='adam',\n    loss='mse',  # измените в зависимости от задачи\n    metrics=['r2_score']\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:44.084188Z","iopub.execute_input":"2025-12-01T15:13:44.084419Z","iopub.status.idle":"2025-12-01T15:13:44.164755Z","shell.execute_reply.started":"2025-12-01T15:13:44.084402Z","shell.execute_reply":"2025-12-01T15:13:44.163959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:44.165535Z","iopub.execute_input":"2025-12-01T15:13:44.165860Z","iopub.status.idle":"2025-12-01T15:13:44.191205Z","shell.execute_reply.started":"2025-12-01T15:13:44.165843Z","shell.execute_reply":"2025-12-01T15:13:44.190444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.callbacks import ModelCheckpoint, EarlyStopping\n\ncheck = ModelCheckpoint(filepath='best_model.keras',\n                        monitor='val_r2_score',\n                        save_weights_only=False,\n                        mode='max', \n                       save_best_only=True)\n\n\nearly_stopping = EarlyStopping(\n    monitor='val_r2_score',\n    patience=10,\n    mode='max')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:35:25.152839Z","iopub.execute_input":"2025-12-01T15:35:25.153176Z","iopub.status.idle":"2025-12-01T15:35:25.158671Z","shell.execute_reply.started":"2025-12-01T15:35:25.153155Z","shell.execute_reply":"2025-12-01T15:35:25.157799Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(\n    x=[X_img_train, X_num_train],  # два входа\n    y=y_train,\n    validation_data=([X_img_val, X_num_val], y_val),\n    epochs=100,\n    batch_size=32,\n    verbose=1,\n    callbacks=[check, early_stopping]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:13:44.198218Z","iopub.execute_input":"2025-12-01T15:13:44.198461Z","iopub.status.idle":"2025-12-01T15:32:48.150821Z","shell.execute_reply.started":"2025-12-01T15:13:44.198441Z","shell.execute_reply":"2025-12-01T15:32:48.150164Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.models import load_model\nfrom sklearn.metrics import r2_score\n\nmodel = load_model('best_model.keras')\npreds_val = model.predict([X_img_val, X_num_val])\nr2_score(y_val, preds_val)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:32:48.152157Z","iopub.execute_input":"2025-12-01T15:32:48.152463Z","iopub.status.idle":"2025-12-01T15:32:52.635073Z","shell.execute_reply.started":"2025-12-01T15:32:48.152445Z","shell.execute_reply":"2025-12-01T15:32:52.634470Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Control","metadata":{}},{"cell_type":"code","source":"preds_control = model.predict([X_img_control, X_num_control])\nr2_score(y_control, preds_control)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:32:52.635885Z","iopub.execute_input":"2025-12-01T15:32:52.636588Z","iopub.status.idle":"2025-12-01T15:32:58.827578Z","shell.execute_reply.started":"2025-12-01T15:32:52.636563Z","shell.execute_reply":"2025-12-01T15:32:58.827013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_con_array = np.array(y_control)\nindexes = y_control.index\nfor i in range(preds_control.shape[0]):\n    print(f'pred: {preds_control[i][0]}    target: {y_con_array[i]}    index: {indexes[i]}    tar name: {df_train.loc[indexes[i]][\"target_name\"]}\\n')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T15:32:58.828332Z","iopub.execute_input":"2025-12-01T15:32:58.828592Z","iopub.status.idle":"2025-12-01T15:32:58.838870Z","shell.execute_reply.started":"2025-12-01T15:32:58.828570Z","shell.execute_reply":"2025-12-01T15:32:58.838042Z"}},"outputs":[],"execution_count":null}]}