Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilotilla

Amazon SageMaker -autopilotti mahdollistaa sen, että organisaatiot voivat nopeasti rakentaa ja ottaa käyttöön päästä päähän -koneoppimismallin (ML) ja päättelyputken vain muutamalla koodirivillä tai jopa ilman mitään koodia ollenkaan kanssa Amazon SageMaker Studio. Autopilotti kuormittaa infrastruktuurin määrittämistä ja koko putkilinjan rakentamiseen kuluvaa aikaa, mukaan lukien ominaisuuksien suunnittelu, mallin valinta ja hyperparametrien viritys.

Tässä viestissä näytämme, kuinka voit siirtyä raakatiedoista vahvaan ja täysin käyttöön otettuun päättelyputkeen Autopilotin avulla.

Ratkaisun yleiskatsaus

Käytämme Lyftin julkinen tietojoukko pyörien jakamisesta Tämä simulaatio ennustaa, osallistuuko käyttäjä vai ei Bike Share for All -ohjelma. Tämä on yksinkertainen binääriluokitusongelma.

Haluamme esitellä, kuinka helppoa on rakentaa automatisoitu ja reaaliaikainen johtopäätös käyttäjien luokittelemiseksi heidän osallistumisensa perusteella Bike Share for All -ohjelmaan. Tätä tarkoitusta varten simuloimme San Franciscon lahden alueella toimivan kuvitteellisen bikeshare-yrityksen päästä-päähän tiedonkeruun ja päättelyn putkilinjaa.

Arkkitehtuuri on jaettu kahteen osaan: tuloputkeen ja päättelyputkeen.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Keskitymme ensisijaisesti ML-putkistoon tämän viestin ensimmäisessä osassa ja tarkastelemme tietojen käsittelyä toisessa osassa.

Edellytykset

Noudata tätä esimerkkiä täyttämällä seuraavat edellytykset:

  1. Luo uusi SageMaker-muistikirjan esiintymä.
  2. Luo Amazon Kinesis Data Firehose toimitusvirta an AWS Lambda muunnostoiminto. Katso ohjeet Amazon Kinesis Firehose Data Transformation AWS Lambdalla. Tämä vaihe on valinnainen ja tarvitaan vain datan suoratoiston simulointiin.

Tietojen etsintä

Ladataan ja visualisoidaan tietojoukko, joka sijaitsee julkisesti Amazonin yksinkertainen tallennuspalvelu (Amazon S3) ämpäri ja staattinen verkkosivusto:

# The dataset is located in a public bucket and static s3 website.
# https://www.lyft.com/bikes/bay-wheels/system-data import pandas as pd
import numpy as np
import os
from time import sleep !wget -q -O '201907-baywheels-tripdata.zip' https://s3.amazonaws.com/baywheels-data/201907-baywheels-tripdata.csv.zip
!unzip -q -o 201907-baywheels-tripdata.zip
csv_file = os.listdir('.')
data = pd.read_csv('201907-baywheels-tripdata.csv', low_memory=False)
data.head()

Seuraava kuvakaappaus näyttää osajoukon tiedoista ennen muuntamista.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Tietojen viimeinen sarake sisältää tavoitteen, jonka haluamme ennustaa, joka on binäärimuuttuja, joka saa joko Kyllä- tai Ei-arvon, mikä osoittaa, osallistuuko käyttäjä Bike Share for All -ohjelmaan.

Katsotaanpa tavoitemuuttujamme jakautumista datan epätasapainoon.

# For plotting
%matplotlib inline
import matplotlib.pyplot as plt
#!pip install seaborn # If you need this library
import seaborn as sns
display(sns.countplot(x='bike_share_for_all_trip', data=data))

Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Kuten yllä olevasta kaaviosta näkyy, tiedot ovat epätasapainossa, ja ohjelmaan osallistuu vähemmän ihmisiä.

Meidän on tasapainotettava tiedot, jotta vältetään liiallinen esittely. Tämä vaihe on valinnainen, koska Autopilot tarjoaa myös sisäisen lähestymistavan luokan epätasapainon automaattiseen käsittelyyn, jonka oletuksena on F1-pisteiden validointimetriikka. Lisäksi, jos päätät tasapainottaa tiedot itse, voit käyttää kehittyneempiä tekniikoita luokkaepätasapainon käsittelyyn, kuten löivät or GAN.

Tätä viestiä varten otannamme enemmistöluokkaa (No) tiedon tasapainotustekniikkana:

Seuraava koodi rikastaa dataa ja aliotostaa yliedustetun luokan:

df = data.copy()
df.drop(columns=['rental_access_method'], inplace=True) df['start_time'] = pd.to_datetime(df['start_time'])
df['start_time'] = pd.to_datetime(df['end_time']) # Adding some day breakdown
df = df.assign(day_of_week=df.start_time.dt.dayofweek, hour_of_day=df.start_time.dt.hour, trip_month=df.start_time.dt.month)
# Breaking the day in 4 parts: ['morning', 'afternoon', 'evening']
conditions = [ (df['hour_of_day'] >= 5) & (df['hour_of_day'] < 12), (df['hour_of_day'] >= 12) & (df['hour_of_day'] < 18), (df['hour_of_day'] >= 18) & (df['hour_of_day'] < 21),
]
choices = ['morning', 'afternoon', 'evening']
df['part_of_day'] = np.select(conditions, choices, default='night')
df.dropna(inplace=True) # Downsampling the majority to rebalance the data
# We are getting about an even distribution
df.sort_values(by='bike_share_for_all_trip', inplace=True)
slice_pointe = int(df['bike_share_for_all_trip'].value_counts()['Yes'] * 2.1)
df = df[-slice_pointe:]
# The data is balanced now. Let's reshuffle the data
df = df.sample(frac=1).reset_index(drop=True)

Jätimme tarkoituksella kategorisia ominaisuuksiamme koodaamatta, mukaan lukien binääritavoitearvomme. Tämä johtuu siitä, että Autopilot huolehtii tietojen koodaamisesta ja purkamisesta puolestamme osana automaattista ominaisuussuunnittelua ja putkien käyttöönottoa, kuten seuraavassa osiossa näemme.

Seuraavassa kuvakaappauksessa on esimerkki tiedoistamme.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Seuraavien kaavioiden tiedot näyttävät muuten normaaleilta, ja bimodaalinen jakauma edustaa kahta huippua aamutunneille ja iltapäivän ruuhka-aikoina, kuten voit odottaa. Tarkkailemme myös vähäistä toimintaa viikonloppuisin ja öisin.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Seuraavassa osiossa syötämme tiedot Autopilotille, jotta se voi suorittaa kokeen puolestamme.

Rakenna binäärinen luokitusmalli

Autopilotti edellyttää, että määritämme tulo- ja lähtökohderyhmät. Se käyttää syöttösäilöä tietojen lataamiseen ja tulostussäilöä artefaktien, kuten ominaisuussuunnittelun ja luotujen Jupyter-muistikirjojen, tallentamiseen. Säilytämme 5 % tietojoukosta mallin suorituskyvyn arvioimiseksi ja validoimiseksi koulutuksen jälkeen ja lataamme 95 % tietojoukosta S3-syöttöämpäriin. Katso seuraava koodi:

import sagemaker
import boto3 # Let's define our storage.
# We will use the default sagemaker bucket and will enforce encryption bucket = sagemaker.Session().default_bucket() # SageMaker default bucket. #Encrypting the bucket
s3 = boto3.client('s3')
SSEConfig={ 'Rules': [ { 'ApplyServerSideEncryptionByDefault': { 'SSEAlgorithm': 'AES256', } }, ] }
s3.put_bucket_encryption(Bucket=bucket, ServerSideEncryptionConfiguration=SSEConfig) prefix = 'sagemaker-automl01' # prefix for ther bucket
role = sagemaker.get_execution_role() # IAM role object to use by SageMaker
sagemaker_session = sagemaker.Session() # Sagemaker API
region = sagemaker_session.boto_region_name # AWS Region # Where we will load our data input_path = "s3://{}/{}/automl_bike_train_share-1".format(bucket, prefix) output_path = "s3://{}/{}/automl_bike_output_share-1".format(bucket, prefix) # Spliting data in train/test set.
# We will use 95% of the data for training and the remainder for testing.
slice_point = int(df.shape[0] * 0.95) training_set = df[:slice_point] # 95%
testing_set = df[slice_point:] # 5% # Just making sure we have split it correctly
assert training_set.shape[0] + testing_set.shape[0] == df.shape[0] # Let's save the data locally and upload it to our s3 data location
training_set.to_csv('bike_train.csv')
testing_set.to_csv('bike_test.csv', header=False) # Uploading file the trasining set to the input bucket
sagemaker.s3.S3Uploader.upload(local_path='bike_train.csv', desired_s3_uri=input_path)

Kun tiedot on ladattu syöttökohteeseen, on aika käynnistää Autopilot:

from sagemaker.automl.automl import AutoML
# You give your job a name and provide the s3 path where you uploaded the data
bike_automl_binary = AutoML(role=role, target_attribute_name='bike_share_for_all_trip', output_path=output_path, max_candidates=30)
# Starting the training bike_automl_binary.fit(inputs=input_path, wait=False, logs=False)

Meidän tarvitsee vain aloittaa kokeilu, on kutsua fit()-metodi. Autopilotti tarvitsee syötteen ja lähdön S3 sijainnin sekä kohdeattribuuttisarakkeen pakollisina parametreina. Ominaisuuden käsittelyn jälkeen Autopilot soittaa Automaattinen SageMaker-viritys löytääksesi parhaan version mallista suorittamalla monia koulutustöitä tietojoukossasi. Lisäsimme valinnaisen max_candidates-parametrin rajoittaaksemme ehdokkaiden määrän 30:een, mikä on koulutustöiden lukumäärä, jonka Autopilot käynnistää erilaisilla algoritmien ja hyperparametrien yhdistelmillä parhaan mallin löytämiseksi. Jos et määritä tätä parametria, sen oletusarvo on 250.

Voimme tarkkailla Autopilotin edistymistä seuraavalla koodilla:

# Let's monitor the progress this will take a while. Go grup some coffe.
from time import sleep def check_job_status(): return bike_automl_binary.describe_auto_ml_job()['AutoMLJobStatus'] def discribe(): return bike_automl_binary.describe_auto_ml_job() while True: print (check_job_status(), discribe()['AutoMLJobSecondaryStatus'], end='** ') if check_job_status() in ["Completed", "Failed"]: if "Failed" in check_job_status(): print(discribe()['FailureReason']) break sleep(20)

Koulutuksen suorittaminen vie jonkin aikaa. Kun se on käynnissä, katsotaanpa Autopilotin työnkulkua.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Käytä seuraavaa koodia löytääksesi parhaan ehdokkaan:

# Let's take a look at the best candidate selected by AutoPilot
from IPython.display import JSON
def jsonView(obj, rootName=None): return JSON(obj, root=rootName, expanded=True) bestCandidate = bike_automl_binary.describe_auto_ml_job()['BestCandidate']
display(jsonView(bestCandidate['FinalAutoMLJobObjectiveMetric'], 'FinalAutoMLJobObjectiveMetric'))

Seuraava kuvakaappaus näyttää tuotoksemme.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Mallimme saavutti 96 prosentin validointitarkkuuden, joten aiomme ottaa sen käyttöön. Voisimme lisätä sellaisen ehdon, että käytämme mallia vain, jos tarkkuus ylittää tietyn tason.

Päätelmäputki

Ennen kuin otamme mallin käyttöön, tutkitaan parasta ehdokastamme ja sitä, mitä valmisteillamme tapahtuu. Katso seuraava koodi:

display(jsonView(bestCandidate['InferenceContainers'], 'InferenceContainers'))

Seuraava kaavio näyttää tuotosiamme.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Autopilot on rakentanut mallin ja pakannut sen kolmeen eri säiliöön, joista jokainen suorittaa peräkkäin tiettyä tehtävää: muunnos, ennustaminen ja käänteinen muunnos. Tämä monivaiheinen päättely on mahdollista a SageMaker-päätelmäputki.

Monivaiheinen päättely voi myös ketjuttaa useita päättelymalleja. Esimerkiksi yksi kontti voi toimia pääkomponenttien analyysi ennen kuin siirrät tiedot XGBoost-säilöön.

Ota päättelyputki käyttöön päätepisteeseen

Käyttöönottoprosessi sisältää vain muutaman rivin koodia:

# We chose to difine an endpoint name.
from datetime import datetime as dt
today = str(dt.today())[:10]
endpoint_name='binary-bike-share-' + today
endpoint = bike_automl_binary.deploy(initial_instance_count=1, instance_type='ml.m5.xlarge', endpoint_name=endpoint_name, candidate=bestCandidate, wait=True)

Määritetään päätepisteemme ennustajaa varten:

from sagemaker.serializers import CSVSerializer
from sagemaker.deserializers import CSVDeserializer
csv_serializer = CSVSerializer()
csv_deserializer = CSVDeserializer()
# Initialize the predictor
predictor = sagemaker.predictor.Predictor(endpoint_name=endpoint_name, sagemaker_session=sagemaker.Session(), serializer=csv_serializer, deserializer=csv_deserializer )

Nyt kun päätepisteemme ja ennustajamme ovat valmiina, on aika käyttää sivuun jättämiämme testaustietoja ja testata mallimme tarkkuutta. Aloitamme määrittelemällä apufunktion, joka lähettää tiedot rivi kerrallaan päätelmäpäätepisteeseemme ja saa vastineeksi ennusteen. Koska meillä on XGBoost mallissa pudotamme kohdemuuttujan ennen CSV-rivin lähettämistä päätepisteeseen. Lisäksi poistimme otsikon testaus-CSV:stä ennen tiedoston läpikäyntiä, mikä on myös toinen vaatimus XGBoostille SageMakerissa. Katso seuraava koodi:

# The fuction takes 3 arguments: the file containing the test set,
# The predictor and finaly the number of lines to send for prediction.
# The function returns two Series: inferred and Actual.
def get_inference(file, predictor, n=1): infered = [] actual = [] with open(file, 'r') as csv: for i in range(n): line = csv.readline().split(',') #print(line) try: # Here we remove the target variable from the csv line before predicting observed = line.pop(14).strip('n') actual.append(observed) except: pass obj = ','.join(line) predicted = predictor.predict(obj)[0][0] infered.append(predicted) pd.Series(infered) data = {'Infered': pd.Series(infered), 'Observed': pd.Series(actual)} return pd.DataFrame(data=data) n = testing_set.shape[0] # The size of the testing data
inference_df = get_inference('bike_test.csv', predictor, n) inference_df['Binary_Result'] = (inference_df['Observed'] == inference_df['Infered'])
display(inference_df.head())

Seuraava kuvakaappaus näyttää tuotoksemme.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Lasketaan nyt mallimme tarkkuus.
Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.

Katso seuraava koodi:

count_binary = inference_df['Binary_Result'].value_counts()
accuracy = count_binary[True]/n
print('Accuracy:', accuracy)

Saamme 92% tarkkuuden. Tämä on hieman pienempi kuin validointivaiheessa saatu 96 %, mutta se on silti tarpeeksi korkea. Emme odota tarkkuuden olevan täsmälleen sama, koska testi suoritetaan uudella tietojoukolla.

Tietojen nauttiminen

Latasimme tiedot suoraan ja määritimme ne harjoittelua varten. Tosielämässä saatat joutua lähettämään tiedot suoraan reunalaitteesta datajärveen ja ladamaan SageMakerin suoraan datajärvestä muistikirjaan.

Kinesis Data Firehose on hyvä vaihtoehto ja yksinkertaisin tapa ladata suoratoistodataa luotettavasti datajärviin, tietovarastoihin ja analytiikkatyökaluihin. Se voi kaapata, muuntaa ja ladata suoratoistodataa Amazon S3:een ja muihin AWS-tietovarastoihin.

Käyttötapaukseemme luomme Kinesis Data Firehose -toimitusvirran, jossa on Lambda-muunnostoiminto, joka tekee kevyen datan puhdistuksen, kun se kulkee virran läpi. Katso seuraava koodi:

# Data processing libraries
import pandas as pd # Data processing
import numpy as np
import base64
from io import StringIO def lambda_handler(event, context): output = [] print('Received', len(event['records']), 'Records') for record in event['records']: payload = base64.b64decode(record['data']).decode('utf-8') df = pd.read_csv(StringIO(payload), index_col=0) df.drop(columns=['rental_access_method'], inplace=True) df['start_time'] = pd.to_datetime(df['start_time']) df['start_time'] = pd.to_datetime(df['end_time']) # Adding some day breakdown df = df.assign(day_of_week=df.start_time.dt.dayofweek, hour_of_day=df.start_time.dt.hour, trip_month=df.start_time.dt.month) # Breaking the day in 4 parts: ['morning', 'afternoon', 'evening'] conditions = [ (df['hour_of_day'] >= 5) & (df['hour_of_day'] < 12), (df['hour_of_day'] >= 12) & (df['hour_of_day'] < 18), (df['hour_of_day'] >= 18) & (df['hour_of_day'] < 21), ] choices = ['morning', 'afternoon', 'evening'] df['part_of_day'] = np.select(conditions, choices, default='night') df.dropna(inplace=True) # Downsampling the majority to rebalance the data # We are getting about an even distribution df.sort_values(by='bike_share_for_all_trip', inplace=True) slice_pointe = int(df['bike_share_for_all_trip'].value_counts()['Yes'] * 2.1) df = df[-slice_pointe:] # The data is balanced now. Let's reshuffle the data df = df.sample(frac=1).reset_index(drop=True) data = base64.b64encode(bytes(df.to_csv(), 'utf-8')).decode("utf-8") output_record = { 'recordId': record['recordId'], 'result': 'Ok', 'data': data } output.append(output_record) print('Returned', len(output), 'Records') print('Event', event) return {'records': output}

Tämä Lambda-toiminto suorittaa valomuunnoksen laitteista suoratoistetusta datasta datajärvelle. Se odottaa CSV-muotoista datatiedostoa.

Käsittelyvaihetta varten lataamme tiedot ja simuloimme tietovirran Kinesis Data Firehoseen Lambda-muunnostoiminnolla ja S3-datajärveemme.

Simuloillaan muutaman rivin suoratoistoa:

# Saving the data in one file.
file = '201907-baywheels-tripdata.csv' data.to_csv(file) # Stream the data 'n' lines at a time.
# Only run this for a minute and stop the cell
def streamer(file, n): with open(file, 'r') as csvfile: header = next(csvfile) data = header counter = 0 loop = True while loop == True: for i in range(n): line = csvfile.readline() data+=line # We reached the end of the csv file. if line == '': loop = False counter+=n # Use your kinesis streaming name stream = client.put_record(DeliveryStreamName='firehose12-DeliveryStream-OJYW71BPYHF2', Record={"Data": bytes(data, 'utf-8')}) data = header print( file, 'HTTPStatusCode: '+ str(stream['ResponseMetadata']['HTTPStatusCode']), 'csv_lines_sent: ' + str(counter), end=' -*- ') sleep(random.randrange(1, 3)) return
# Streaming for 500 lines at a time. You can change this number up and down.
streamer(file, 500) # We can now load our data as a DataFrame because it’s streamed into the S3 data lake:
# Getting data from s3 location where it was streamed.
STREAMED_DATA = 's3://firehose12-deliverybucket-11z0ya3patrod/firehose/2020'
csv_uri = sagemaker.s3.S3Downloader.list(STREAMED_DATA)
in_memory_string = [sagemaker.s3.S3Downloader.read_file(file) for file in csv_uri]
in_memory_csv = [pd.read_csv(StringIO(file), index_col=0) for file in in_memory_string]
display(df.tail())

Puhdistaa

On tärkeää poistaa kaikki tässä harjoituksessa käytetyt resurssit kustannusten minimoimiseksi. Seuraava koodi poistaa luomamme SageMaker-päätelmäpäätepisteen sekä lataamamme koulutus- ja testaustiedot:

#Delete the s3 data
predictor.delete_endpoint() # Delete s3 data
s3 = boto3.resource('s3')
ml_bucket = sagemaker.Session().default_bucket()
delete_data = s3.Bucket(ml_bucket).objects.filter(Prefix=prefix).delete()

Yhteenveto

ML-insinöörit, datatieteilijät ja ohjelmistokehittäjät voivat käyttää Autopilotia johtopäätösputkiston rakentamiseen ja käyttöön ilman vähän tai ei ollenkaan ML-ohjelmointikokemusta. Autopilotti säästää aikaa ja resursseja käyttämällä datatieteen ja ML:n parhaita käytäntöjä. Suuret organisaatiot voivat nyt siirtää suunnitteluresursseja pois infrastruktuurin määrittämisestä mallien parantamiseen ja yrityskäyttötapausten ratkaisemiseen. Startup-yritykset ja pienemmät organisaatiot voivat aloittaa koneoppimisen ilman ML-asiantuntemusta.

Aloita SageMaker Autopilotin käyttö katsomalla Tuotesivu tai käytä SageMaker Autopilotia SageMaker Studiossa.

Suosittelemme myös oppimaan lisää muista SageMakerin tarjoamista tärkeistä ominaisuuksista, kuten Amazon SageMaker -ominaisuuskauppa, joka integroituu Amazon SageMaker -putkistot luoda, lisätä ominaisuushakua ja -hakua sekä käyttää uudelleen automatisoituja ML-työnkulkuja. Voit ajaa useita Autopilot-simulaatioita erilaisilla ominaisuuksilla tai kohdemuunnelmilla tietojoukossasi. Voit lähestyä tätä myös dynaamisena ajoneuvon allokointiongelmana, jossa mallisi yrittää ennustaa ajoneuvojen kysyntää ajan (kuten vuorokaudenajan tai viikonpäivän) tai sijainnin tai molempien yhdistelmän perusteella.


Tietoja Tekijät

Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.Doug Mbaya on Senior Solution -arkkitehti, joka keskittyy dataan ja analytiikkaan. Doug tekee tiivistä yhteistyötä AWS-kumppaneiden kanssa auttaen heitä integroimaan data- ja analytiikkaratkaisuja pilveen. Dougin aiempi kokemus sisältää AWS-asiakkaiden tukemisen kyydissä ja ruuan toimituksissa.

Automatisoi jaettu pyörien ja skootterien luokitusmalli Amazon SageMaker Autopilot PlatoBlockchain Data Intelligencen avulla. Pystysuuntainen haku. Ai.Valerio Perrone on Applied Science Manager, joka työskentelee Amazon SageMakerin automaattisen mallin virityksen ja autopilotin parissa.

Aikaleima:

Lisää aiheesta AWS-koneoppiminen