{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":10200,"databundleVersionId":868375,"sourceType":"competition"}],"dockerImageVersionId":25160,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"#CNN usando Keras ¡Desde cero!\n \n* Este es un problema de reconocimiento/clasificación de imágenes complejas dibujadas por personas.\n* Para ello se utilizó una CNN especializada en reconocimiento de imágenes.\n* En lugar de una red preentrenada, el modelo básico se creó utilizando Keras.\n* Para el preprocesamiento de datos y la entrada/salida de datos, consulte el kernel ['Image-Based CNN'] (https://www.kaggle.com/jpmiller/image-based-cnn).\n* Debido a limitaciones en el preprocesamiento de datos, se utilizaron 2000 conjuntos de datos por clase. Sería bueno desarrollar un modelo utilizando un generador para obtener más datos.\n* En el caso del modelo CNN, se utilizaron 3 capas de convolución-Pooling.\n​","metadata":{}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\nimport ast\nimport os\nfrom glob import glob\nfrom tqdm import tqdm\nfrom dask import bag\nimport cv2\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow import keras\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten\nfrom keras.layers import Conv2D, MaxPooling2D\nfrom keras.metrics import top_k_categorical_accuracy\nfrom keras.metrics import sparse_top_k_categorical_accuracy\nfrom keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-11-23T15:54:34.146869Z","iopub.execute_input":"2023-11-23T15:54:34.147214Z","iopub.status.idle":"2023-11-23T15:54:35.478236Z","shell.execute_reply.started":"2023-11-23T15:54:34.147153Z","shell.execute_reply":"2023-11-23T15:54:35.477411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Primero forme un diccionario para que coincida con la etiqueta y el nombre de clase de los datos predichos.\n\n* ims_per_class especifica la cantidad de datos que incluyen el conjunto de entrenamiento + prueba. Aquí se utilizaron 2000 para cada clase.\n* Datos: Se utilizaron un total de 340*2000=680000.","metadata":{}},{"cell_type":"code","source":"classfiles=os.listdir('../input/train_simplified/')\nnumstonames={i : v[:-4].replace(' ','_') for i , v in enumerate(classfiles)}\n\nnum_class=340\nimheight,imwidth=32,32\nims_per_class=2000","metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","execution":{"iopub.status.busy":"2023-11-23T15:54:35.480086Z","iopub.execute_input":"2023-11-23T15:54:35.480359Z","iopub.status.idle":"2023-11-23T15:54:35.624539Z","shell.execute_reply.started":"2023-11-23T15:54:35.480297Z","shell.execute_reply":"2023-11-23T15:54:35.623802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Convierta el trazo dado en una línea usando cv2 y vuelva a convertirlo en una imagen de 32*32 píxeles.","metadata":{}},{"cell_type":"code","source":"def stroke_to_img(strokes):\n    img=np.zeros((256,256))\n    for each in ast.literal_eval(strokes):\n        for i in range(len(each[0])-1):\n            cv2.line(img,(each[0][i],each[1][i]),(each[0][i+1],each[1][i+1]),255,5)\n    img=cv2.resize(img,(32,32))\n    img=img/255\n    return img","metadata":{"execution":{"iopub.status.busy":"2023-11-23T15:54:35.625822Z","iopub.execute_input":"2023-11-23T15:54:35.626054Z","iopub.status.idle":"2023-11-23T15:54:35.631417Z","shell.execute_reply.started":"2023-11-23T15:54:35.626015Z","shell.execute_reply":"2023-11-23T15:54:35.630493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Stoke 확인하기\n* Haga flotar dos imágenes de clase aleatorias y verifique las imágenes y etiquetas usando la función Stroke_to_img.","metadata":{}},{"cell_type":"code","source":"rd=np.random.randint(340)\nranclass=numstonames[rd]\nranclass=ranclass.replace('_',' ')\nrdpath='../input/train_simplified/'+ranclass+'.csv'\none=pd.read_csv(rdpath,usecols=['drawing','recognized','word'],nrows=10)\none=one[one.recognized==True].head(2)\nname=one['word'].head(1)\nstrk=one['drawing']\npic=[]\nfor s in strk:\n    pic.append(stroke_to_img(s))\nname=name.values\n\nfig,axarr = plt.subplots(1,2)\ntitle_obj = plt.title(name)\nplt.getp(title_obj, 'text')           \naxarr[0].imshow(pic[1])\naxarr[1].imshow(pic[0])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-23T15:54:35.632597Z","iopub.execute_input":"2023-11-23T15:54:35.632815Z","iopub.status.idle":"2023-11-23T15:54:36.085275Z","shell.execute_reply.started":"2023-11-23T15:54:35.632778Z","shell.execute_reply":"2023-11-23T15:54:36.083874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Forma una matriz completa que incluye Train Set y Test Set.","metadata":{}},{"cell_type":"code","source":"train_grand=[]\nclass_paths = glob('../input/train_simplified/*.csv')\nfor i , c in enumerate(tqdm(class_paths[0:num_class])):\n    train=pd.read_csv(c,usecols=['drawing','recognized'],nrows=ims_per_class*2)\n    train=train[train.recognized==True].head(ims_per_class)\n    imagebag=bag.from_sequence(train.drawing.values).map(stroke_to_img)\n    trainarray=np.array(imagebag.compute())\n    trainarray=np.reshape(trainarray,(ims_per_class,-1))\n    labelarray=np.full((train.shape[0],1),i)\n    trainarray=np.concatenate((labelarray,trainarray),axis=1)\n    train_grand.append(trainarray)\n\ntrain_grand=np.array([train_grand.pop() for i in np.arange(num_class)])\ntrain_grand=train_grand.reshape((-1,(imheight*imwidth+1)))\n\ndel trainarray\ndel train","metadata":{"execution":{"iopub.status.busy":"2023-11-23T15:54:36.087199Z","iopub.execute_input":"2023-11-23T15:54:36.087926Z","iopub.status.idle":"2023-11-23T16:01:08.481027Z","shell.execute_reply.started":"2023-11-23T15:54:36.087852Z","shell.execute_reply":"2023-11-23T16:01:08.480137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Establezca la proporción para los datos de validación y divídala después de Random Shuffle.","metadata":{}},{"cell_type":"code","source":"valfrac=0.2\ncutpt=int(valfrac*train_grand.shape[0])\n\nnp.random.shuffle(train_grand)\ny_train, x_train=train_grand[cutpt:,0],train_grand[cutpt:,1:]\ny_val,x_val=train_grand[0:cutpt,0], train_grand[0:cutpt,1:]\n\ndel train_grand\n\nx_train=x_train.reshape(x_train.shape[0],imheight,imwidth,1)\nx_val=x_val.reshape(x_val.shape[0],imheight,imwidth,1)","metadata":{"execution":{"iopub.status.busy":"2023-11-23T16:01:08.482589Z","iopub.execute_input":"2023-11-23T16:01:08.482843Z","iopub.status.idle":"2023-11-23T16:01:10.909814Z","shell.execute_reply.started":"2023-11-23T16:01:08.482799Z","shell.execute_reply":"2023-11-23T16:01:10.908869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#CNN 모델 설계\n\n* INPUT -> [[CONV -> RELU]-> POOL]*3-> [FC-> RELU]-> FC\n\n* Para reconocer la imagen, se realizó la convolución tres veces para crear una estructura jerárquica para cada parte.\n* En convolución, la activación se realizó con Relu y la activación de clase final usó softmax para 340 etiquetas.","metadata":{}},{"cell_type":"code","source":"model =Sequential()\nmodel.add(Conv2D(32,kernel_size=(3,3),padding='same',activation='relu',input_shape=(imheight,imwidth,1)))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\nmodel.add(Dropout(0.1))\nmodel.add(Conv2D(64,kernel_size=(3,3),padding='same',activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\nmodel.add(Dropout(0.1))\nmodel.add(Conv2D(64,kernel_size=(3,3),padding='same',activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\nmodel.add(Dropout(0.1))\nmodel.add(Flatten())\nmodel.add(Dropout(0.2))\nmodel.add(Dense(680,activation='relu'))\nmodel.add(Dense(num_class,activation='softmax'))\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2023-11-23T16:01:10.911531Z","iopub.execute_input":"2023-11-23T16:01:10.911864Z","iopub.status.idle":"2023-11-23T16:01:11.197269Z","shell.execute_reply.started":"2023-11-23T16:01:10.911802Z","shell.execute_reply":"2023-11-23T16:01:11.196543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* En el caso de la categoría de etiqueta, se utilizó 'sparse_categorical_crossentropy' porque no se utilizó la codificación One-Hot por motivos de memoria.\n* Reduzca la tasa de aprendizaje cada vez que se llama a la devolución de llamada con reduceLROnPlat.\n* val_acc se utilizó como condición para la parada anticipada.\n* El optimizador utiliza  'adam'","metadata":{}},{"cell_type":"code","source":"def top_3_accuracy(x,y):\n    t3=sparse_top_k_categorical_accuracy(x,y,3)\n    return t3\n\nreduceLROnPlat=ReduceLROnPlateau(monitor='val_loss',factor=0.5,patience=3,verbose=1,mode='auto',min_delta=0.005,cooldown=5,min_lr=0.0001)\nearlystop=EarlyStopping(monitor='val_acc',mode='max',patience=5)\ncallbacks=[reduceLROnPlat,earlystop]\n\nmodel.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['accuracy',top_3_accuracy])\n\nhistory=model.fit(x=x_train,y=y_train,batch_size=32,epochs=80,validation_data=(x_val,y_val),callbacks=callbacks,verbose=1)","metadata":{"execution":{"iopub.status.busy":"2023-11-23T16:01:11.198781Z","iopub.execute_input":"2023-11-23T16:01:11.19901Z","iopub.status.idle":"2023-11-23T16:59:54.15839Z","shell.execute_reply.started":"2023-11-23T16:01:11.19897Z","shell.execute_reply":"2023-11-23T16:59:54.157652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loss & Accuracy Graph\n* Entrenamiento, precisión de validación y gráfico de pérdidas.\n","metadata":{}},{"cell_type":"code","source":"acc=history.history['acc']\nval_acc=history.history['val_acc']\nloss= history.history['loss']\nval_loss=history.history['val_loss']\n\nepochs=range(1,len(acc)+1)\n\nplt.plot(epochs,acc,'bo',label='Training acc')\nplt.plot(epochs,val_acc,'b',label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(epochs,loss,'bo',label='Training loss')\nplt.plot(epochs,val_loss,'b',label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-11-23T16:59:54.159791Z","iopub.execute_input":"2023-11-23T16:59:54.160108Z","iopub.status.idle":"2023-11-23T16:59:54.726725Z","shell.execute_reply.started":"2023-11-23T16:59:54.16005Z","shell.execute_reply":"2023-11-23T16:59:54.725927Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ttvlist=[]\nreader=pd.read_csv('../input/test_simplified.csv',index_col=['key_id'],chunksize=2048)\nfor chunk in tqdm(reader,total=55):\n    imagebag=bag.from_sequence(chunk.drawing.values).map(stroke_to_img)\n    testarray=np.array(imagebag.compute())\n    testarray=np.reshape(testarray,(testarray.shape[0],imheight,imwidth,1))\n    testpreds=model.predict(testarray,verbose=0)\n    ttvs=np.argsort(-testpreds)[:,0:3]\n    ttvlist.append(ttvs)\nttvarray=np.concatenate(ttvlist)\npred_df=pd.DataFrame({'first': ttvarray[:,0],'second':ttvarray[:,1],'third':ttvarray[:,2]})\npred_df=pred_df.replace(numstonames)\npred_df['words']=pred_df['first']+' '+pred_df['second']+' '+pred_df['third']\n\nsub=pd.read_csv('../input/sample_submission.csv',index_col=['key_id'])\nsub['word']=pred_df.words.values\n","metadata":{"execution":{"iopub.status.busy":"2023-11-23T16:59:54.728629Z","iopub.execute_input":"2023-11-23T16:59:54.729202Z","iopub.status.idle":"2023-11-23T17:01:22.314742Z","shell.execute_reply.started":"2023-11-23T16:59:54.729078Z","shell.execute_reply":"2023-11-23T17:01:22.314015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('keras.h5')","metadata":{"execution":{"iopub.status.busy":"2023-11-23T17:01:22.316424Z","iopub.execute_input":"2023-11-23T17:01:22.316762Z","iopub.status.idle":"2023-11-23T17:01:22.472127Z","shell.execute_reply.started":"2023-11-23T17:01:22.316699Z","shell.execute_reply":"2023-11-23T17:01:22.471361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}