機械学習の設計パターン(マクロ&ミクロ)

自分用のメモです。

マクロなパターン(≒システム、運用)

tech.mercari.com

ミクロなパターン(≒前処理、EDA、モデル構築)

courses.edx.org

www.kaggle.com

  • 前処理
    • cell_17: 経験則ぽいEDA
    • cell_25: columnsの選択基準がよくわからない
    • cell_27: サンプルの半分以上が目的変数に対して強い相関を持つ特徴量の抽出。17/81
    • cell_30: outlier(外れ値)排除
    • cell_: 目的変数SalesPriceを対数に変換
  • モデル作成
    • cell_40: 一般的な正規化StandardScaler()の他に RobustScaler(), PowerTransformer() ?? も別途実施。結局使っているのは、PowerTransformer()だけ。変数のスケールを変えて分布を正規分布(ガウス分布)の形に変えてくれる変換らしい。
    • cell_42~46: 推定器としてregressor()を5種類生成。選択基準は不明。
    • ell_47: () で 5つのregressorをスタッキング。

scikit-learn.org

www.kaggle.com

www.kaggle.com

機械学習で参考になった情報

機械学習を勉強するにあたって参照した情報源の自分用メモです。 (手を付けたが完了できなかった項目への自戒もこめて)

履修済みで役にたっている情報

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

  • 作者:岡谷 貴之
  • 発売日: 2015/04/08
  • メディア: 単行本(ソフトカバー)
深層学習という言葉が流行りだしたときに一番最初に読んだ本。というか日本語で自分が読めそうな本はこれしかなかった。

deep learning だけでなく、sklearnを使った shallow learning の習得に役立つ

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

  • 作者:斎藤 康毅
  • 発売日: 2016/09/24
  • メディア: 単行本(ソフトカバー)
3冊出ているうちの1冊目。理解できるか不安になりながら、おっかなびっくり読んだが丁寧に書いてあってよい本。

PythonとKerasによるディープラーニング

PythonとKerasによるディープラーニング

  • 作者:Francois Chollet
  • 発売日: 2018/05/28
  • メディア: 単行本(ソフトカバー)
tensorflowを直接使うのは辛そうだったので、kerasの使い方を習得するために購入。筆者はkerasの作者なので安心。

イラストで学ぶ ディープラーニング 改訂第2版 (KS情報科学専門書)

イラストで学ぶ ディープラーニング 改訂第2版 (KS情報科学専門書)

  • 作者:山下 隆義
  • 発売日: 2018/11/19
  • メディア: 単行本(ソフトカバー)
イラストがたくさん載ってるけど結構情報量は多くて参考になる

一つ一つの項目の情報量は少なめだが、その分読みやすく、他の本のインデックスとしても使える。

苦手意識のあるpandasの使い方の参考になった

scikit-learnとTensorFlowによる実践機械学習

scikit-learnとTensorFlowによる実践機械学習

  • 作者:Aurélien Géron
  • 発売日: 2018/04/26
  • メディア: 単行本(ソフトカバー)
実践向き

仕事ではじめる機械学習

仕事ではじめる機械学習

実践向き

Kaggleで勝つデータ分析の技術

Kaggleで勝つデータ分析の技術

Kaggleに挑戦しようとして読んだ。タイタニック以外もサブミットできるところまでは進めた。

実践チュートリアル 決定木とランダムフォレスト student.codexa.net 決定木をなんとなくしか理解していなかったので。

実践チュートリアル XGBoost student.codexa.net KaggleでXGBoostがよく使われるということなので勉強してみた。

courses.edx.org IBMの講座。内容は難しくないが機械学習全体のフローを再確認するのに役立った。

着手したが未完了で役にたちそうな本

パターン認識と機械学習 上

パターン認識と機械学習 上

長くかかりそう

これは写経して問題も解く予定

深層学習

深層学習

ドラフト版をざっくりはみた。数式でちゃんと理解したい人向け。

www.coursera.org Kaggleでの勝ち方。自分にはまだレベルが高くて挫折。Kaggleをある程度やってから受けた方がよさそう。


Lecture 1 - Welcome | Stanford CS229: Machine Learning (Autumn 2018) ご存知Stanford大のAndrew Ng先生の2018年の講座の動画。

www.udemy.com www.udemy.com www.udemy.com www.udemy.com 日本語だし、内容は分かりやすいのですが、自分が欲張っていくつも登録した結果、消化できていない。

未着手だがよく紹介されているのできっと参考になる

はじめてのパターン認識

はじめてのパターン認識

  • 作者:平井 有三
  • 発売日: 2012/07/31
  • メディア: 単行本(ソフトカバー)
はじパタ。

鈍器。

あんまり自分には合わなかったが参考になる人もいるはず

(この情報を見た時の自分の実力や求めるものと合わなかっただけで、フィットする人もいるはずです。)

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

FreeRTOS Code Reading (Arduino編, #3)

今回は予定通り vTaskStartScheduler() から呼ばれる xTaskCreate() を読んでいく。 vTaskStartScheduler() からの の呼び出し。

  • variantHooks.cpp: void vTaskStartScheduler( void )
        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                configIDLE_TASK_NAME,
                                configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
  • tack.h: 関数宣言
    BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
  • 関数引数
引数型 名前 内容、意味
TaskFunction_t pxTaskCode PRiVate アイドルタスク(関数)、
const char * const pcName タスク名。configIDLE_TASK_NAME, "IDLE"。
const configSTACK_DEPTH_TYPE usStackDepth タスクのスタックサイズ。configMINIMAL_STACK_SIZE, 192byte
void * const pvParameters タスクへの引数。null pointer
UBaseType_t uxPriority 0x00。portPRIVILEGE_BIT
TaskHandle_t * const pxCreatedTask NULL。xIdleTaskHandle

次はxTaskCreate() の実装。

  • tack.c
    BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask 
    {
...
        #if( portSTACK_GROWTH > 0  )
        ...
        #else /* portSTACK_GROWTH */
        {
        StackType_t *pxStack;

            /* Allocate space for the stack used by the task being created. */
            pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */

            if( pxStack != NULL )
            {
                /* Allocate space for the TCB. */
                pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */

                if( pxNewTCB != NULL )
                {
                    /* Store the stack location in the TCB. */
                    pxNewTCB->pxStack = pxStack;
                }
                else
                {
                    ...
                }
            }
            else
            {
                ...
            }
        }
        #endif /* portSTACK_GROWTH *

順にみていくが、pvPortMalloc()はヒープからメモリを確保していると思うので詳細は後で見る。

pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 

タスクのためのスタックメモリ領域を確保。サイズは StackType_t を usStackDepth個 だけ。 次にタスク制御バッファ(Tack Control Buffer。TCB_t)の領域を確保する。

pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );

#defineを辿るとTCB_tの実体は下記のようである。

  • tack.c:
typedef struct TaskControlBlock_t
{
    volatile StackType_t    *pxTopOfStack;  /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */

    ListItem_t          xStateListItem;     /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
    ListItem_t          xEventListItem;     /*< Used to reference a task from an event list. */
    UBaseType_t         uxPriority;         /*< The priority of the task.  0 is the lowest priority. */
    StackType_t         *pxStack;           /*< Points to the start of the stack. */
    char                pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
}
メンバの型 メンバ変数名 内容、意味
volatile StackType_t *pxTopOfStack タスクのスタックの最後のアイテムのアドレスへのポインタ。TCB構造体のメンバの最初に置く必要がある
ListItem_t xStateListItem ステート(状態)リスト。Ready, Blocked, Suspended
ListItem_t xEventListItem イベントリストからタスクを参照するのに使われる
UBaseType_t uxPriority 優先度。0が最低。
StackType_t *pxStack スタックの先頭アドレスへのポインタ
char pcTaskName[ configMAX_TASK_NAME_LEN ] デバッグ

xStateListItem、xEventListItem の使われ方がまだよくわからない。

pxNewTCB->pxStack = pxStack;

タスク用のスタック領域(pxStack )と、タスク制御用のバッファ(pxNewTCB )が確保出来たら、タスク制御用のバッファのスタック領域に割り当てる。

後回しにしていたpvPortMalloc()を詳細にみてみる。

  • heap_3.c
void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn;

    vTaskSuspendAll();
    {
        pvReturn = malloc( xWantedSize );
        traceMALLOC( pvReturn, xWantedSize );
    }
    ( void ) xTaskResumeAll();

    #if( configUSE_MALLOC_FAILED_HOOK == 1 )
    {
        if( pvReturn == NULL )
        {
             ...
        }
    }
    #endif

    return pvReturn;
}

メモリをヒープから確保する。下記順に実行されている

  1. タスクを全部サスペンドする(vTaskSuspendAll()
  2. malloc してヒープからメモリをxWantedSize [byte] 確保する。
  3. サスペンドしたタスクをレジュームする(xTaskResumeAll()

まず、1. の全タスクのサスペンドする処理を読んでみる。

  • tasks.c:
void vTaskSuspendAll( void )
{
    /* A critical section is not required as the variable is of type
    BaseType_t.  Please read Richard Barry's reply in the following link to a
    post in the FreeRTOS support forum before reporting this as a bug! -
    http://goo.gl/wu4acr */
    ++uxSchedulerSuspended;
}

コードは1行しかないけど、コメントが何やら書いてあるので辿ってみる。 goo.gl

要約すると、最初にこの記述は問題があるのでは?という質問に対して、問題ない、と回答している。 質問者が下記質問を投げかけている。

AVR(Arduino UNOとか), ARM Cortex M ではこの操作(++uxSchedulerSuspended; のこと)をコンパイラーが以下のように処理する

  • (メモリから)uxSchedulerSuspendeded をCPUレジスタにロードする
  • レジスタ値をインクリメントする
  • レジスタ値を (メモリ上の)uxSchedulerSuspendeded にストアする

これは 明らかに NOT ATOMIC じゃない。(訳注:3命令の途中でタスク切り替えが発生し得る etc.) だから、アトミックなインクリメント機械語命令がないすべてのプラットフォームに対してportATOMIC_INCREMENT()マクロを実装することを提案する。

それに対する richardbarry さん(中の人?)の答えがこれ。

各タスクは自分自身のコンテキストを管理していて、かつコンテキストスイッチはこの値(uxSchedulerSuspended)がゼロでないときは発生しない。 従って、レジスタバックからメモリーへの書き込みはアトミックであり、問題にならない。

さらに丁寧に例を挙げて説明してくれている。

uxSchedulerSuspended がゼロから始まるシナリオを考えてみる。

  • (メモリから)uxSchedulerSuspendeded をCPUレジスタにロードする

さて、コンテキストスイッチは他のタスクが実行することを発生させる。そのタスクが同じ変数を使用する。そのタスクはその変数をゼロとしてみる。なぜなら、その変数はオリジナルタスクから更新されていないから。

ここまでは理解できる。

そのあとで、オリジナルタスクが再度実行したとする。これは以下のときのみ発生する

  • uxSchedulerSuspended が再度ゼロに設定された
  • かつ、オリジナルタスクがCPUレジスタの内容、これらはコンテキストスイッチアウトされた時のまま保持された内容であり、これを再度実行した

従って、レジスタにリードされた値はまだ(メモリ上の)xuSchedulerSuspendedの値と同じである。

うーん。この条件がよくわからない。 さらにこの後に続く質問者のコメントをみると、 uxSchedulerSuspended はカウンターではなくバイナリ(1 or 0)で扱われているから問題ないね。 と納得しているのでなんかそういうことなんだと思うけど、あとでもう一度考えてみます。

  • レジスタ値をインクリメントする

  • レジスタ値を (メモリ上の)uxSchedulerSuspendeded にストアする 他のタスクにこの変数が使用されたとしても、uxSchedulerSuspendeded は正しい値である1になる。

malloc() は stdlib.h で宣言されている。malloc実装はあとでみる。 mallocを解説した動画www.youtube.comも参考になる。

traceMALLOC() は、traceMALLOC が定義されておらずArduino UNO版では実態はないようだ。

#ifndef traceMALLOC
    #define traceMALLOC( pvAddress, uiSize )
#end

最後にxTaskResumeAll() を読もうと思ったけど、長いので次回に持ち越し。

従って、次回はvTaskStartScheduler() -> xTaskCreate() -> pvPortMalloc() から呼ばれた `xTaskResumeAll()' から続きを読んでいきます。 今回はいろいろ積み残しがありました。

FreeRTOS Code Reading (Arduino編, #2)

xTaskCreate() 関数を読む前に予定を変えてWindows環境でAruduino IDEでのビルドについて確認します。

Arduino IDEのメニューから、ファイル->環境設定->より詳細な情報を表示する->コンパイル にチェックを入れると、 下記にようにビルド時の詳細情報が表示されるようになります。

"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10809 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard" "-IC:\Users\hogehoge\Documents\Arduino\libraries\FreeRTOS\src" "C:\Users\hogehoge\AppData\Local\Temp\arduino_build_353041\sketch\arduino_freertos_sample.ino.cpp" -o "C:\Users\hogehoge\AppData\Local\Temp\arduino_build_353041\sketch\arduino_freertos_sample.ino.cpp.o"

上の例では、下記フォルダでビルドが実行され、ファイルが生成されています

"C:\Users\hogehoge\AppData\Local\Temp\arduino_build_353041

arduino_build_folder

上記フォルダで、avr-objdump.exe を実行することで、生成されたアセンブリ言語を見ることもできます

objdump

必要に応じて利用していきたいと思います。

次回こそxTaskCreate() 関数を読み進めます。

FreeRTOS Code Reading (Arduino編, #1)

興味があるのでFreeRTOSのソースコードを読んでみる。 あとで修正するかもしれませんが、しばらくは体裁が整っていない自分用のメモです。

なぜ読むか?

RTOSの実装に興味があり、Arduino版ならコード量の少なく読みやすそうだったので。

ソースコードはここ。github.com MPU(atmega328p)のdatasheetはここ。https://avr.jp/user/DS/PDF/mega328P.pdf

もしくはここ。http://akizukidenshi.com/download/ds/microchip/atmega328.pdf

読み方、ソースコード引用の方針

どこから読み始めるか

161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf に variantHook.cpp から読めと書いてあるのでそこから始める。 (↑は昔書いたメモだけど、見当たらないorz)

読む

  • Arduino_FreeRTOS_Library\src\variantHooks.cpp
extern void setup(void);
extern void loop(void);

/*-----------------------------------------------------------*/

void initVariant(void) __attribute__ ((OS_main));
void initVariant(void)
{
#if defined(USBCON)
    USBDevice.attach();
#endif

    setup();        // the normal Arduino setup() function is run here.
    vTaskStartScheduler(); // initialise and run the freeRTOS scheduler. Execution should never return here.
}

setup(), loop()はexternされていて、実体は Arduinoのsketchが参照される。

  • task.c
void vTaskStartScheduler( void )
{
BaseType_t xReturn;

    /* Add the idle task at the lowest priority. */
    #if( configSUPPORT_STATIC_ALLOCATION == 1 )
    {
        ...
    }
    #else
    {
        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                configIDLE_TASK_NAME,
                                configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
    }
    #endif /* configSUPPORT_STATIC_ALLOCATION */

configSUPPORT_STATIC_ALLOCATION は, config次第だが多分0(要確認)。

#ifndef configSUPPORT_STATIC_ALLOCATION
    /* Defaults to 0 for backward compatibility. */
    #define configSUPPORT_STATIC_ALLOCATION 0
#endi

スケジューラをタスクの1つとして登録する。

        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                configIDLE_TASK_NAME,
                                configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
    if( xReturn == pdPASS )
    {
        ...

        /* Interrupts are turned off here, to ensure a tick does not occur
        before or during the call to xPortStartScheduler().  The stacks of
        the created tasks contain a status word with interrupts switched on
        so interrupts will automatically get re-enabled when the first task
        starts to run. */
        portDISABLE_INTERRUPTS();

        #if ( configUSE_NEWLIB_REENTRANT == 1 )
        {
            /* Switch Newlib's _impure_ptr variable to point to the _reent
            structure specific to the task that will run first. */
            _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
        }
        #endif /* configUSE_NEWLIB_REENTRANT */

        xNextTaskUnblockTime = portMAX_DELAY;
        xSchedulerRunning = pdTRUE;
        xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;

        /* If configGENERATE_RUN_TIME_STATS is defined then the following
        macro must be defined to configure the timer/counter used to generate
        the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS
        is set to 0 and the following line fails to build then ensure you do not
        have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
        FreeRTOSConfig.h file. */
        portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

        traceTASK_SWITCHED_IN();

        /* Setting up the timer tick is hardware specific and thus in the
        portable interface. */
        if( xPortStartScheduler() != pdFALSE )
        {
            /* Should not reach here as if the scheduler is running the
            function will not return. */
        }
        else
        {
            /* Should only reach here if a task calls xTaskEndScheduler(). */
        }
    }
    else
    {
        ...
    }
  1. スケジューラのタスクの生成に成功したか(xReturn == pdPASS)を確認する
  2. xPortStartScheduler() を呼ぶまで割り込み禁止にする
        xNextTaskUnblockTime = portMAX_DELAY;
        xSchedulerRunning = pdTRUE;
        xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
  • xNextTaskUnblockTime は、...
  • xSchedulerRunning は、スケジューラが動作中はpdTRUEvoid vTaskEndScheduler( void ) が呼ばれると pdFALSE に設定される
  • xTickCount は、次のスケジュールのタスクの割り込みまでの時間。
        portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

        traceTASK_SWITCHED_IN();

この2つのマクロはdefaultはカラ。

        if( xPortStartScheduler() != pdFALSE )
  • port.c
BaseType_t xPortStartScheduler( void )
{
    /* Setup the relevant timer hardware to generate the tick. */
    prvSetupTimerInterrupt();

    /* Restore the context of the first task that is going to run. */
    portRESTORE_CONTEXT();

    /* Simulate a function call end as generated by the compiler.  We will now
   jump to the start of the task the context of which we have just restored. */
    __asm__ __volatile__ ( "ret" );

    /* Should not get here. */
    return pdTRUE;
}
//initialize watchdog
void prvSetupTimerInterrupt( void )
{
    //reset watchdog
    wdt_reset();

    //set up WDT Interrupt (rather than the WDT Reset).
    wdt_interrupt_enable( portUSE_WDTO );
}
  • prvSetupTimerInterrupt() は、WDT(Watch Dog Timer)をリセットし、WDT割り込みを有効にしている。 ** `wdt_rest(), wdt_interrupt_enable()' は要確認
  • portRESTORE_CONTEXT() は、CPUレジスタを戻して(pop)、xPortStartScheduler() が呼ばれる前の状態(context)に戻している。
  • ret を発行して関数から戻る。

ここまででスケジューラタスクの登録し、実行した状態になった。

次回は、少し戻ってスケジューラタスクの生成処理を読み解いてみる。

        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                configIDLE_TASK_NAME,
                                configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */

Googleカレンダーをスマホと同期させる

改めていうことじゃないですが、Googleカレンダー便利ですね。 スマホとも同期できるので一元管理できていいですね。

でも、自分の環境では問題が・・・

用途毎に複数のカレンダーを作ったり、公開されているカレンダーを登録したりして、 複数のカレンダがーが場合にブラウザでは全てのカレンダーが見れるけど、 同期設定しているつもりのスマホのカレンダーアプリでは見れるカレンダーと見れないカレンダーがありました。 以前に軽く調べたときはよくわからなかったけど、 もう一度調べ直しても見たら解決したのでφ(..)

そのような内容なので、スマホのカレンダーアプリでGoogleカレンダーと"全く"同期できない場合は 他の記事を検索した方がよいです。

iPhone/iPad

iPhone/iPadはこの記事で紹介されている同期設定のページが ビンゴでした。 weekly.ascii.jp

…ただ、自分でGoogleカレンダーのヘルプからたどろうとすると スマートフォンまたはタブレットでのカレンダーの同期 - カレンダー ヘルプApple カレンダーとの同期→他のカレンダーの同期→カレンダーの同期 となかなかたどり着けないページにある。

Android

Androidスマホではカレンダーアプリとして ジョルテを使っていますが、 このアプリからでは設定できないようだ。 Googleカレンダーでないと同期するカレンダーを選択できないようだ。Googleカレンダー"アプリ"は全く使ってなかったので気づかなかったけど… 具体的にはGoogleカレンダーアプリを開いて以下の手順を実行すれば、ジョルテでも同期されるようになりました。 メニュー → 設定 → 同期させたいカレンダーを選択 → 同期をONに変更

f:id:zinziroge:20160220111720p:plain:w300 f:id:zinziroge:20160220111714p:plain:w300 f:id:zinziroge:20160220111652p:plain:w300 f:id:zinziroge:20160220111647p:plain:w300