エンジニアMのAI学習記録(2018年1月分)

最終更新:2019年01月11日 公開:2018年01月05日
こちらは、Webに関連するエンジニア向けの記事です。
当社のWeb関連技術の公開と採用活動のために掲載しています。

(2018年2月2日更新)

みなさんこんにちは、エンジニアのMです。
これは当社の技術やAIに興味のある方に向けた日誌になります。
今月も毎週更新していきます、よろしくお願いします。

1月4日

■ PHP

統計学は一旦置いておいて、PHP(+MySQL)について少し勉強する。
数式で疲れた頭をほぐすのに、プログラミング言語の入門書はちょうどいい。

  • PHP+MySQLマスターブック (ISBN978-4-8399-4759-0)

■ CPUに内在する脆弱性について

  • Intel Management Engineなどに8個の脆弱性が発見:PC Watch [リンク]

Intel MEに脆弱性が存在したという話は記憶に新しいが、今度はプロセッサの投機的実行(speculative execution)に関する脆弱性が見つかったという。

  • Intel製CPUに内在する脆弱性問題の根は深く「すべてのプロセッサが安全性と高速性を両立できない問題を抱える」との指摘:Gigazine [リンク]
  • Intel、AMD、ARMなどのCPUに深刻な脆弱性、影響を巡る報道で混乱広がる:マイナビニュース [リンク]
  • IntelなどのCPUに脆弱性を発見 業界各社が協力して対応を急ぐ:livedoor NEWS [リンク]
  • CPUにハッカー攻撃への脆弱性 テクノロジー各社が対応急ぐ:BBC [リンク]
  • Meltdown and Spectre [リンク]

今回の脆弱性は、「Meltdown」と「Spectre」と名付けられた2つであり、

  • Meltdown:1995年以降のほとんどのIntel製プロセッサ
  • Spectre:Intel、AMD、ARM各社のプロセッサ(事実上すべてのマイクロプロセッサに影響するとの記述も)

が内包するとのこと。
当初はIntel製プロセッサの問題との報道もあったようだが、実際にはARM、AMD製プロセッサにも影響するものであった。
Meltdownに関しては、2011年リリースのIntel製プロセッサでテストに成功したとのこと。
AMDの技術者は「AMD製CPUは投機的実行における推測的なメモリの参照が許可されていないためメルトダウンの影響を受けない」とのメッセージを発信している。
他方Spectreに関しては、「Meltdown and Spectre」ウェブページ内に「Spectreは悪用することも難しいが、対策することも難しい」との記述がある。
こちらについては情報がほとんど出ていないので、続報を待つ必要がありそうだ。

■ 脆弱性の影響は?

Linux用のMeltdownへの対策パッチを適用すると、プロセッサの性能が5~30%低下すると言われている。
一般ユーザーへの影響は、この性能低下が一番身近な問題となろう。
AMD製プロセッサの性能向上が著しい中、Intel MEに続き、より深刻な脆弱性「Meltdown」が発覚したことはIntelにとって大きな痛手だ。
WPA2の脆弱性が発覚したときも大きな話題となったが、今年もセキュリティ関係の話題は(悪い意味で)尽きないようである。

1月5日

■ PHP

「Meltdown」と「Spectre」を調べていたらあまり進まなかったので、今日は入門書を終わらせるつもりで進める。

■ CPU脆弱性に関する追記

情報がかなり集まって来ているようなので、追記する。

  • Meltdown and Spectre FAQ: Fix for Intel CPU flaws could slow down PCs and Macs : PCWorld [リンク]

Windowsへのパッチ前後の比較がこちらの動画内で紹介されているが、SSDの処理性能低下が目立つ程度だ。
Macへのパッチ適用による影響は軽微との記事もある。
Linuxの開発者Linux Torvaldsもメーリングリストで、「あなたが行う処理に依存する。一部の負荷は、ユーザー空間内で全て処理される限り、ほとんど影響しない。」としている。
ここで一つ重要なのはPCID(Process-context identifier)と呼ばれる技術にプロセッサが対応しているか否かである。この技術は、Haswell(4th-gen)以降のIntel製プロセッサであれば使用可能とのこと。「古いIntelプロセッサは大きく影響を受ける可能性がある」という報道は、これが関係するものと思われる。
ここまでで、比較的新しいシステムを使う一般ユーザーはほぼ影響を受けないと断言できそうだ。
しかし、一部のアプリケーション(特に仮想化タスクやデータセンター、クラウドワークロード)は他のアプリケーションより影響を受けるという。
これらを活用している企業にとっては、実際にどれほどの影響があるのか、さらなる情報が必要だ。


※様々な記事の情報を総合した上で記述していますが、現時点での情報なので誤りが含まれる可能性があります。常に最新の情報を確認するようにしてください。


私が普段使っているプロセッサに、こういった脆弱性が見つかったということが衝撃だったので納得いくまで調べてみた。


※1/10追記:

  • 投機実行の脆弱性修正、Haswell世代以前では性能への影響大:PC Watch[リンク]
  • Understanding the performance impact of Spectre and Meltdown mitigations on Windows Systems : Microsoft Secure[リンク]

「Windows 7」, 「Windows 8」はユーザーカーネルとのやり取りが多いレガシーなOSであるため、CPUの世代を問わず「Windows 10」利用時と比べパフォーマンスが低下する。
また「Haswell」(第4世代、例:Intel i7-4790K)及びそれ以前(Core2、第3世代までのCore iシリーズなど)のCPUでは「Windows 10」を利用していても、一部のユーザーで体感できる程度のパフォーマンス低下が起きる。「Windows 7」、「Windows 8」と「Haswell」以前のCPUの組合せが最も悪く、大部分のユーザーが体感できるほどのパフォーマンス低下が起きる。
わたしは、

  • Windows 7 or 8で「5%」(Windows 10 を基準として)
  • Haswell 以前のCPUで「15%」or それより後のCPUで「5%」

くらい劣化するのではと予想する(ワークロードによってはそれ以上)。
最悪のケースに該当する方は、実際の使用感を確認した上でPCの更新を検討したほうがいいかもしれない。


1月9日

■ プリンタの調子が悪い

ネットワーク経由での印刷が遅い(なかなか開始されない)、無意味な文字列が印刷される、といった不具合に見舞われる。
ケーブルを繋ぎ直した後に再起動したところ問題は起きなくなったが、また起きないとも限らない。
プリンタの故障、修理に関して、互換インク・トナーの性能を比較検証したレポートが出てきたので紹介したいと思う。

  • 【レポート】キヤノンレーザープリンタ ロシア仕向けトナーカートリッジ 印刷比較試験:アリオン [リンク]
  • 【レポート】キヤノンフォトプリンタ インクカセット・用紙 ベンチマーク試験:アリオン [リンク]

性能に顕著な差が現れているのがわかる。
プリンタはインク代で回収するビジネスモデルであることはよく知られている。
値段相応かはさておき、純正品の性能は十分に高いものであることは確かだろう。
不自然な安さには必ず訳がある。「安かろう悪かろう」である。

1月10日

■ WindowsUpdateに脆弱性対策パッチが来ていたので適用してみた

このパッチによって一般的な用途で一番影響を受けると言えるのが、メモリ、ストレージの操作であった。
そこで予め確保しておいた「7-zip」のベンチマーク結果を比較したところ、平均で5%程度の性能低下が見られた。
圧縮時に一瞬速度が半減する挙動が見られるなど、パッチの影響を感じるものであった。
また、日頃から「PyCharm」で小説生成モデルの学習を回しているのだが、チェックポイントからの再開が遅くなったように感じる。
元々仮想メモリも含めて大量にメモリを消費していたので、「用途による」部分に該当したと言えるか。

■ 機械学習に絡む線形代数の知識についておさらい

しばらく横道に逸れていたので、機械学習に関する知識の復習をする。
記憶の薄いところについては、重点的に確認する。

1月11日

■ 機械学習や分析手法の復習

線形代数の復習をざっくりと終わらせたところで、また機械学習について忘れている部分を思い出す。
ある程度間を置きつつ振り返ることで、知識を染み込ませていければと思う。

1月12日

■ CPU脆弱性に関する補足

  • AMD,「CPUの脆弱性」に対策するマイクロコードのリリースを予告:4gamer [リンク]

Variant2への対策をAMDも行うということで、AMD製プロセッサにおいても性能低下が起きると記事では述べられている。
ただし原文には「optional microcode」とあるので、主に万が一に備えるためのサーバー管理者、企業向けと考えることもできるだろう。
以前にAMDは悪用は困難との見解を示していたが、ユーザーの不安を取り除くためにオプションを用意するという姿勢は好感が持てる。


※オプションということでも、私個人としてはセキュリティリスクを最小にするために適用することをおすすめする。AI時代のセキュリティリスクは未知数な部分が多い。


■ 引き続き機械学習や関連分野の復習

引き続き復習をしていく。
便利なウェブサービスに実装の大部分を委ねることになったとしても、基礎的な部分についてはやはり理解しておかなければならないだろう。


1月15日

■ 情報理論についても軽く触れる

情報理論の範囲で、機械学習などに関連のある部分について調べる。
情報理論の一部については以前に少し勉強したことがあるので、今更ながらの確認作業といったところだ。
以下は特に参考になったと感じた記事のリンクである。

  • 情報理論を視覚的に理解する (1/4) :POSTD [リンク]

1月16日

■ 機械学習の復習&Kerasについて調べる

ある程度機械学習について復習が終わった後で、Kerasについて調べてみようと思う。
既存の手法をそのまま扱っていくことのほうが多いと思われるので、少ない記述量で検証できるKerasは覚えておいて良さそうだと感じた。
元々、KerasはTheanoやTensorFlowをバックエンドとして動くものという知識はあった。
今はTensorFlowとの統合も進んでいて、TensorFlowを入れるだけで tf.keras からアクセスできるようになっているらしい(確かにAPIドキュメントを見た時にあった)。

■ TensorFlow更新

TensorFlowに統合されたKerasを使おうとバージョンを確認したところ、1.5.0rc1がリリースされていたので更新する。
バージョンを 1.3 から上げるのを忘れていたことも分かったので、この機会にRC版まで1.4を飛ばして上げてしまう。
TensorFlow 1.5.0rc1 を使用するためには、

  • CUDA 9.0
  • cuDNN 7

のダウンロードも必要となる。少々手間取ったが無事に動作することを確認した。

1月17日

■ 花の画像分類をしてみる

kaggleで見つけてきたデータセットを使って、画像分類をさせてみる。
データがJpeg形式で画像サイズもまちまちなので、学習に使えるように処理しなければならない。

TensorFlowのCIFAR-10用チュートリアルを出来る限り使いまわして学習させたいので、そのフォーマットに則ったバイナリファイルを作ることにする。
どういう挙動をするか知らない関数が多数入っているので、下手にいじると泥沼になると判断した。

■ 成果

データバイナリの生成にだいぶ手間取ったがCIFAR-10用コードに放り込むことができた。
そこでlossがNaNになる問題が発生して頭を悩ませたが、こちらで値を変更していたNUM_CLASSESを5から10に戻したら解決した。
10と100で使う想定のもので、10未満の値ではうまく動かなくなるのかもしれない。
未使用の5クラスへの出力が無くなる方向で学習は進むので、これでも問題は無い。

1月18日

■ 昨日の続き

昨日のバイナリデータ作成コードを、テスト用データの分割をするように改変した。とりあえず、1クラスあたり100個をテストデータ側に振り分けた。
32×32~128×128まで4種類のバイナリデータを用意した。
それぞれについて十分な時間を与えて検証していく。
元々のデータセットは写真が雑多に詰め込まれている(人が写っていたり、花が小さすぎたりする)ので、私が見ても怪しいものが割とある。
それも踏まえた上で、分類精度を確認していく。

  • 32×32 : Step 100K : Precision 0.736
  • 64×64 : Step 22K : Precision 0.801
  • 96×96 : Step 22K : Precision 0.809
  • 128×128 : Step 21K : Precision 0.809

CIFAR-10と違い、花という同じカテゴリ内で品種を見分けるタスクなので、32×32では画像サイズが足りていない可能性が高い。
判別不可能なデータも混じっていると考えれば、それなりの精度か。

■ 大きい画像データに対して層数を増やして試す

conv, pool, normの1セットを追加して、学習にどういう影響があるか試してみる。
単に追加するだけでは変化がなかったので、以下の基準でデータを除外するところから手をつける。

  • 花が小さくしか映っていない
  • 花以外の要素が多い
  • ぼやけている
  • データを正方形に整形するときに花が消える

4000枚程度の数で、学習に不適な画像が混じっていると影響が大きいのではと考えられる。
モデル適用時にどういうデータを入力するかによって、許されるデータ整理の範囲は変わってくる。この場合は、ある程度きれいなデータが入力されることを前提とした学習となる。

1月19日

■ 改善できそうな部分をいろいろいじる

Learning Rateの減衰がほぼ機能していなかった点や、バッチサイズ変更などの調整をして、昨日整理したデータで学習させる。
学習速度と精度のバランスを考えて、64×64と96×96の画像を使用する。

■ Lossの値が途中でNaNになる問題

試行錯誤の過程で、ある程度学習が進んだとき急にLossの値が跳ね上がる現象に遭遇した。
RNNを使ったモデルでPreprexityがNaNになったことはあったが、それとは何か違う現象のように思える。

■ 経過

  • データ選別後64×64 : Step 21500 : Loss < 0.3 : Precision = 0.840
  • データ選別後96×96 : Step 52000 : Loss < 0.2 : Precision = 0.855

過学習の傾向が表れる前の数字を示している。
Learning Rateが減衰し始める前の段階でも、データ選別前の学習経過より5%程度高い精度を示していた。
テストデータに振り分ける数は変えずに、学習用データの数だけ700個ほど減らした状態で改善が見られたので、前処理の重要さが理解できる。
あとは大きいサイズの画像に合わせたモデルに修正できれば良かったのだが、突然Loss値がNaNになる問題が厄介だ。


1月22日

■ 画像分類続き

128×128の画像に対しても学習を試す。
画像を整理する前とどれほど変化があるだろうか。
待ち時間は人工知能の応用分野について調べる。

  • 64×64 : Step 21.5k : Loss < 0.3 , Precision = 0.840
  • 96×96 : Step 52k : Loss < 0.2 , Precision = 0.855
  • 128×128 : Step 100k : Loss < 0.07 , Precision = 0.870

6時間半かけて10万ステップ分の学習を完了した。
今回の128×128の画像に対する学習で Precision が最大の時、P = 0.875であった。
十分な学習プロセスを経ると、高精細な画像のほうが精度が向上するようだ。
しかしその分学習にかかる時間も非常に長くなるので、目的や計算機の能力、納期との兼ね合いで上手く決定する必要があるだろう。

1月23日

■ ドロップアウトを適用してみる

ドロップアウトを全結合層に適用して、変化を見る。
今日の待ち時間はCNNを用いた物体検出について調べる。

  • 64×64 , Dropout=0.2 , ノード数 384-192 : Step 120k , Loss < 0.1 , Precision = 0.830
  • 64×64 , Dropout=0.5 , ノード数 768-384 : Step 140k , Loss < 0.1 , Precision = 0.834

Learning Rateの減衰も適宜調整してある。
後者で一時 Precision = 0.850 を記録する場面はあったが、今回の例ではあまり有効では無かったようだ。
全結合層を調整するより、特徴抽出のほうに工夫が必要ということだろう。

1月24日

■ 畳み込み層を変更してみる

畳み込み層を調整して変化を見る。
元のサンプルコードが32×32のCIFAR用で、今試しているのはそれより4倍以上画素数が多いデータである。
重みの初期値を変更してLossがNaNになる問題は暫定的に解決済みなので、いろいろいじってみたいと思う。

  • 64×64, チャンネル数128 : Step 40k , loss < 0.2 , Precision = 0.830
  • 96×96, チャンネル数96 : Step 50k , loss < 0.3 , Precision = 0.840

単にチャンネル数を増やしただけでは、悪化する結果となった。
全結合層の前に別のフィルターを設定して並列化しても、効果は得られず(学習が上手く進まなかっただけの可能性もあるが)。
Resnet のような他の手法を取り入れて試してみる頃合いか。

1月25日

■ 特徴抽出側にドロップアウトを適用してみる

全結合層に適用しても有効性は無かったので、今度はその前の段階に適用してどういう変化があるか確認する。

入力サイズ 64×64, ドロップアウト 20%

  • Step 95k , Loss < 0.20 , Precision = 0.852
  • Step 160k , Loss < 0.10 , Precision = 0.859
  • Step 240k , Loss < 0.05 , Precision = 0.848

入力サイズ 64×64, ドロップアウト 50%

  • Step 50k , Loss < 0.50 , Precision = 0.852
  • Step 100k , Loss < 0.30 , Precision = 0.844
  • Step 140k , Loss < 0.20 , Precision = 0.850

(比較用)入力サイズ 64×64, ドロップアウト無し

  • Step 35k , Loss < 0.30 , Precision = 0.846
  • Step 70k , Loss < 0.15 , Precision = 0.846
  • Step 90k , Loss < 0.12 , Precision = 0.840

ドロップアウトは、畳み込み→プーリング→正規化の後と、畳み込み→正規化→プーリングの後に適用している。
特徴抽出にドロップアウトを適用したことで、若干の性能改善が見られる。
ドロップアウト20%を適用した場合では、最終的に Precision = 0.85 付近で安定していた。途中で打ち切ったドロップアウト50%の場合でも、おそらく同じあたりに収束すると見られる。
Precision の最大値も1%程高い数値が得られているので、特徴抽出に対するドロップアウトの有用性を示せたと言える。

1月26日

■ 画像サイズを変えて確認

ドロップアウトの有用性について、1段階大きな画像サイズについても試してみて確認する。

入力サイズ 96×96, ドロップアウト 20%

  • Step 90k , Loss < 0.30 , Precision = 0.859
  • Step 125k , Loss < 0.20 , Precision = 0.861
  • Step 145k , Loss < 0.15 , Precision = 0.865
  • Step 180k , Loss < 0.12 , Precision = 0.861

ドロップアウト無しの場合について、近いStep数をかけたデータが無いので比較しづらいが、少なくとも結果が悪くなってはいないようだ。


1月29日

■ 画像分類テストの継続

次の実験に使うデータ収集の合間に、引き続き花の画像分類モデルで色々実験する。
前回有効なことが確認できたドロップアウトはそのまま使用して、畳み込み層を変更して精度がどう変化するか確認する。

特徴抽出部に畳み込み(フィルタサイズ7×7)+プーリング(サイズ5×5, ストライド3)+正規化(変更なし)という一連の処理を追加し、元の特徴抽出と併せて全結合層に流し込むことにした。
2種類の特徴抽出層を用意してミックスすることで、性能が向上するかどうか確かめる。

画像サイズ96 x 96, ドロップアウト20%

  • Step 25k : Loss < 0.50 , Precision = 0.873
  • Step 50k : Loss < 0.30 , Precision = 0.859
  • Step 70k : Loss < 0.20 , Precision = 0.869
  • Step 85k : Loss < 0.15 , Precision = 0.867
  • Step 100k : Loss < 0.10 , Precision = 0.865

初期の学習率を変更したのでStepによる比較はできないが、全体として効果は薄そうな印象だ。
Precisionのピーク値が高く出ているのは、たまたま上手く分類されただけなのだろう。
モデルを支障のない範囲で複雑化できるのであれば、ニューラルネットに判断を任せて投げてみるのはありなのかもしれない。

1月30日

■ より大きな画像サイズでも試してみる

昨日は大きなフィルタを追加してその精度を試してみたので、今度はその効果がより現れやすそうな大きな画像に対しても試してみる。
待ち時間は「プリンシプルオブプログラミング」を読むなどして過ごす。

画像サイズ 128 x 128, ドロップアウト20%

  • Step 25k : Loss < 0.5 , Precision = 0.848

秒間3ステップしか進まない状態で、一つの目安としているステップ数100kまで後7時間はかかる。結局効果はなさそうだという結論にして、検証はストップする。

1月31日

■ より小さい画像ではどうか

データ選別前は精度が極端に低かった32×32の画像に対して、色々試して比較する。


画像サイズ 32 x 32, ドロップアウト 20%, 追加フィルタ無し

  • Step 200k : Loss < 0.03, Precision = 0.801
  • Step 350k : Loss < 0.02, Precision = 0.789

画像サイズ 32 x 32, ドロップアウト 0%, 追加フィルタ無し

  • Step 50k : Loss < 0.150, Precision = 0.785
  • Step 100k : Loss < 0.040, Precision = 0.760
  • Step 200k : Loss < 0.015, Precision = 0.768
  • Step 250k : Loss < 0.010, Precision = 0.764

画像サイズ 32 x 32, ドロップアウト 20%, 追加フィルタ有り

  • Step 10k : Loss < 0.400, Precision = 0.805
  • Step 60k : Loss < 0.150, Precision = 0.799
  • Step 100k : Loss < 0.050, Precision = 0.797
  • Step 150k : Loss < 0.030, Precision = 0.791
  • Step 200k : Loss < 0.020, Precision = 0.801
  • Step 300k : Loss < 0.015, Precision = 0.795

画像サイズ 32 x 32, ドロップアウト 0%, 追加フィルタ有り

  • Step 10k : Loss < 0.300, Precision = 0.801
  • Step 50k : Loss < 0.080, Precision = 0.758
  • Step 100k : Loss < 0.030, Precision = 0.762
  • Step 200k : Loss < 0.010, Precision = 0.762
  • Step 300k : Loss < 0.009, Precision = 0.756

この画像サイズでも、ドロップアウトは有効に機能しているようだ。
ログを見る限り、追加フィルタ有りのほうが早いうちから高い精度を記録していた。
これは、32 x 32というサイズでは情報が不足するところを、追加フィルタが補ったためと考えていいだろう。逆に大きい画像に対しては情報が過剰となり、過学習の原因を作ったと考えられる。
追加フィルタを用意した場合、学習の進行速度はおよそ2/3になっていた。パラメータが多い分、Loss値の収束も遅い。

■ 結局追加したフィルタは必要だったのか

特定の状況では機能していたが、基本的には不要だったと言える。
素人考えながら機能した場面があったことは収穫だったか。
良かれと思って情報を増やしたところで、ニューラルネットが期待に答えてくれるわけではなかった。なかなか気難しいものである。

2月1日

■ 全結合層のドロップアウトを復活させてみる

追加フィルタはイマイチな結果だったので、次は全結合層のドロップアウトをもう一度試してみることにする。

画像サイズ 64×64, ドロップアウト20%(両方)

  • Step 20k : Loss < 0.50, Precision = 0.840
  • Step 50k : Loss < 0.30, Precision = 0.840
  • Step 100k : Loss < 0.15, Precision = 0.854
  • Step 200k : Loss < 0.03, Precision = 0.852

過学習しているわけでは無さそうだが、効果も無さそうだ。
全結合層のノード数を半分にして試してみる。これでちょうどいい具合になるかどうか。

画像サイズ 64×64, ドロップアウト20%(両方), ノード数 192-96(元は384-192)

  • Step 20k : Loss < 0.40, Precision = 0.846
  • Step 50k : Loss < 0.25, Precision = 0.838
  • Step 100k : Loss < 0.15, Precision = 0.846
  • Step 150k : Loss < 0.06, Precision = 0.840
  • Step 177k : Loss < 0.04, Precision = 0.854
  • Step 200k : Loss < 0.03, Precision = 0.850

先程と似たような傾向となった。ノード数を減らしても、ドロップアウトを全結合層に適用しても計算速度はほとんど変わっていない。精度が下がっている以上、全結合層にドロップアウトを適用するのは無意味だったと結論づける。

2月2日

■ ResNetを試してみたが

公開されていたコードを改変してResNetを試してみることにした。

  • GitHub – xuyuwei/resnet-tf
    : ResNet Implementation in TensorFlow [リンク]

CIFAR-10のPickle版を使うコードだったので、以前のバイナリ生成ツールを改変してPickle版を生成。
学習が回せるように最低限の修正を施して、ResNet56をエポック数50で回してみた。画像サイズはコードを流用できるように32 x 32とした。
結果、Accuracy = 0.78125 と出力された。
違うところが多く、以前のCNNと単純な比較はできずどう評価していいのか分からない。
別作業の間に回せることを期待していたのだが、もっと大規模に改変しなければならないようだ。

■ 畳み込み層を重ねてみたが

ResNetは一旦置いておく。
VGG-16というモデルに倣って、畳み込み層をもう一つずつ重ねて回してみた。
しかし、どうしても学習が停滞してしまう。
元々本題では無かったがこれはこれで気になるので、後でまた試行錯誤してみたいと思う。


アバター画像
フォーム作成クラウドサービス「Formzu(フォームズ)」を運営しているフォームズ株式会社です。
オフィスで働く方、ホームページを運営されている皆様へ
仕事の効率化、ビジネススキル、ITノウハウなど役立つ情報をお届けします。
-->
  • 【初めての方へ】Formzuで仕事の効率化
  • 【初めての方へ】メールフォームについて