Сколько культур вы можете распознать? Для многих большинство сельскохозяйственных культур - это просто «растения», и различение их будет похоже на исследование. Информация о том, что растет на посевных площадях, очень важна для людей, таких как политики в области сельского хозяйства, страховые компании, фермеры, розничные продавцы продуктов питания и т. Д. Своевременное знание информации поможет им скорректировать свои стратегии в отношении разработки политики, ценообразования на страхование, выращивания принятие решений более разумно и эффективно.

Карты посева - самый прямой способ получить такую ​​информацию. Картирование посевов на основе дистанционного зондирования является одним из основных методов составления карт посевов. Ученые Министерства сельского хозяйства США использовали наблюдения дистанционного зондирования в качестве входных данных и использовали модели классификации изображений для создания бесшовных карт культур, таких как CDL (слой данных о пахотных землях). Однако одним из основных недостатков традиционного метода классификации изображений является то, что обученные модели не могут хорошо обобщать. Таким образом, одним из популярных направлений исследований является поиск модели, которую можно многократно повторно использовать на новых данных для построения карт культур без какой-либо помощи в наземных исследованиях. Здесь задействовано машинное обучение, особенно глубокое обучение, которое, как предполагается, будет лучше универсально применимо после обучения.

Мы предложили эту Ag-Net в качестве идеи проекта ESIP GSoC и получили большой вклад от наших талантливых студентов. Вы можете проверить их результаты в этом репозитории Ag-Net GitHub (включая Jupyter Notebooks). В этой статье мы сделаем вывод из этих результатов об общей процедуре использования U-Net, Keras (на основе Tensorflow) для автоматической классификации изображений Landsat в карты культур в Python. В основном он состоит из трех этапов:

  1. Создание модели U-Net

Существует несколько разных версий U-Net с разной конфигурацией. В этом случае построенная U-Net должна принимать 7 каналов Landsat в качестве входных данных и выводить однополосное изображение того же размера (ширина * высота). Отображение представляет собой преобразование изображения в изображение, при котором каждый пиксель изображений Landsat преобразуется в пиксель кадрирования со значением, указывающим его тип. Основанный на архитектуре Keras, пример кода показан ниже:

from keras.activations import softmax
from keras.layers.core import Layer, Dense, Dropout, Activation, Flatten, Reshape, Permute
from keras.layers import Input, merge, Convolution2D, MaxPooling2D, UpSampling2D, Reshape, core, Dropout,GlobalMaxPooling2D
from keras.layers import Add,Multiply
from keras import backend as K
def conv2d_block(input_tensor, n_filters, kernel_size=3,strides=1,batchnorm=True):
    x = Conv2D(filters=n_filters, kernel_size=(kernel_size, kernel_size),strides=(strides, strides),padding="same", kernel_initializer="he_normal")(input_tensor)
    if batchnorm:
        x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.1)(x)
    return x
def encoder_decoder(x1,ni, kernel_size=3, batchnorm=True,times=None):
  x=GlobalMaxPooling2D()(x1)
  x=Reshape(target_shape=(1,1,times))(x)
  x=Conv2D(filters=ni//2, kernel_size=(kernel_size, kernel_size),padding="same", kernel_initializer="he_normal")(x)
  x=LeakyReLU(alpha=0.1)(x)
  x=Conv2D(filters=ni, kernel_size=(kernel_size, kernel_size),padding="same", kernel_initializer="he_normal")(x)
  x=Activation('sigmoid')(x)
  
  x2=Conv2D(filters=ni, kernel_size=(kernel_size, kernel_size),padding="same", kernel_initializer="he_normal")(x1)
  x2=Activation('sigmoid')(x2)
  
  
  x11=Multiply()([x1,x2])
  x12=Multiply()([x1,x])
  x13=Add()([x11,x12])
  
  return x13
  
def DownBlock(x,ni,nf, kernel_size=3, batchnorm=True,down=None):
  inp=x
  x=conv2d_block(x,nf,3,2)
  x=conv2d_block(x,nf,3)
  x=Add()([x,conv2d_block(inp,nf,3,2)])
  if down is not None:
    return encoder_decoder(x,nf, kernel_size=3, batchnorm=True,times=128)
  else:
    return x
  
def UpBlock(down,cross,ni,nf, kernel_size=3, batchnorm=True,down1=None):
  x=Conv2DTranspose(filters=nf, kernel_size=(3, 3),strides=(2,2),padding="same", kernel_initializer="he_normal")(down)
  print(x)
  print(cross)
  x=concatenate([x,cross])
  x=conv2d_block(x,nf,3)
  if down1 is not None:
    return encoder_decoder(x,nf, kernel_size=3, batchnorm=True,times=256)
  else:
    return x
def get_unet(input_img, n_filters=128, dropout=0.15, batchnorm=True):
  d1=DownBlock(input_img,7,128,3, True,12)
  d2=DownBlock(d1,128,256)
  d3=DownBlock(d2,256,512)
  d4=DownBlock(d3,512,1024)
  u1=UpBlock(d4,d3,1024,512)
  u2=UpBlock(u1,d2,512,256,3,True,12)
  u3=UpBlock(u2,d1,256,128)
  
  outputs = Conv2DTranspose(filters=255, kernel_size=(3,3),strides=(2,2),padding="same", kernel_initializer="he_normal")(u3)
  outputs = core.Reshape((128*128,255))(outputs)
  outputs = core.Activation('softmax')(outputs)
   
  model = Model(inputs=[input_img], outputs=[outputs])
  return model

2. Подготовка данных для обучения

Мы использовали Ag-Net-Dataset, сгенерированный из сцены Landsat 8, снятой 2 сентября 2015 года. В нем четыре папки: input, input_32bit, input_rgb и target. Входная папка содержит все семь полос сцены в 16 битах. Input_32bit содержит все семь полос сцены в 32-битном формате. Input_rgb содержит плитки истинного цвета сцены. Люди могут выбрать любую из трех входных папок для сопряжения с целевой папкой для создания своего набора обучающих данных. Все изображения во входной папке и целевых папках точно совпадают по местоположению. Пространственное разрешение точно такое же (30 метров).

3. Обучение

Одна из самых сложных задач в обучении U-Net - это потоковая передача изображений в U-Net. Есть определенные способы сделать это. Python предоставляет очень простой в использовании метод чтения многомерных массивов из файлов изображений. Массивы (массивы numpy) будут преобразованы в определенный формат матрицы, например, (batch_size, band_count, width, height, classes). Соответствующий выходной массив будет преобразован в некоторые аналогичные формы с категоризованным массивом вероятностей. Сопоставление между входными и выходными массивами должно точно совпадать пиксель за пикселем. В противном случае обучение будет признано недействительным.

def get_data(ids,batch_size):
  while True:
    ids_batches = [ids[i:min(i+batch_size,len(ids))] for i in range(0, len(ids), batch_size)] 
    #ids_out_batches = [ids_out[j:min(j+batch_size,len(ids_out))] for j in range(0, len(ids_out), batch_size)]
    # Load images
    for b in range(len(ids_batches)):
      #print(b)
      #print(":")
      #print(ids_batches[b])
      k=-1
      X = np.zeros((len(ids_batches[b]), im_height, im_width, 7), dtype=np.float32)
      y = np.zeros((len(ids_batches[b]), im_height*im_width, 255), dtype=np.float32)
      for c in range(len(ids_batches[b])):
        k=k+1
        #temp1=np.zeros((1,7),dtype=np.float32)
        for r in range(1,7):
          img = load_img(path_train_input + 'lc8' + ids_batches[b][c][3:-4] + '_' + str(r) + '.tif', color_mode="grayscale")
          x_img = img_to_array(img)
          x_img = resize(x_img, (128, 128), mode='constant', preserve_range=True)
          for p in range(128):
            for q in range(128):
              #print(x_img[p][q]/255)
              X[k][p][q][r-1]=x_img[p][q]/255
          
        #k=k+1
        # Save images
        #X[k, ..., 0] = temp1 / 255  

        # Load masks

        mask = img_to_array(load_img(path_train_output+ids_batches[b][c], color_mode="grayscale"))
        mask = resize(mask, (128, 128), mode='constant', preserve_range=True)
        
        inc=-1
        for p in range(128):
          for q in range(128):
            num=int(mask[p][q])
            temp=np.zeros((255), dtype=np.float32)
            temp[num]=1
            inc=inc+1
            y[k][inc]=temp
            print

      yield X,y

Для обучения мы скомпилировали U-Net, используя алгоритм Адама в качестве оптимизатора, 0,1 в качестве скорости обучения, category_crossentropy в качестве функции потерь.

model.compile(optimizer=Adam(lr=0.1), loss="categorical_crossentropy", metrics=["categorical_accuracy"])
model.summary()

Данные будут отправлены в U-Net с помощью следующего кода:

x_tr,y_tr = get_data(train_ids[0:2], batch_size=4)
results = model.fit(x=x_tr,y=y_tr, batch_size=4, epochs=50, verbose=1)

После обучения в течение десятков эпох обучение могло быть остановлено, если точность обучения и точность тестирования достигли ожидаемого порога.

4. Тестирование

Воспользуйтесь обученным U-Net, мы могли бы протестировать его на нескольких изображениях для проверки. Результатом U-Net является карта вероятностей, которую необходимо суммировать с использованием функции max (тип культуры с наибольшей вероятностью будет принимать пиксель). Мы могли бы использовать изображение большего размера и нарезать его на плитки, передать каждую плитку в U-Net, чтобы получить предсказанные карты урожая, и, наконец, объединить все карты листов в большую карту. В результате получается однотонный растр вида:

Чтобы сделать его читабельным, мы применяем к слою легенду USDA NASS. Карта будет отображена в:

Мы протестировали U-Net на нескольких сценах Landsat и получили удовлетворительные результаты. Общая точность по сравнению с CDL составляет около 72% ~ 85% (все пиксели). Вообще говоря, точность по основным культурам, таким как кукуруза и соя, относительно выше, чем по другим культурам и типам почвенного покрова.

Ссылки

Сан, З., Ди, Л. и Фанг, Х., 2019. Использование рекуррентной нейронной сети с долговременной краткосрочной памятью в классификации земного покрова на временных рядах слоев данных Landsat и Cropland. Международный журнал дистанционного зондирования, 40 (2), стр.593–614.

Вс, З .. (30 января 2019 г.). Некоторые основы глубокого обучения в сельском хозяйстве (версия 1). ESIP. Https://doi.org/10.6084/m9.figshare.7631615.v1

Блокноты Jupyter

Agriculture Net.ipynb Аюш Пателя

САНКАЛП МИТТАЛ Ag-Net.ipynb