建築構法計画

東京大学工学部建築学科の講義「建築構法計画」スライドを参考にして記事としてまとめた。

建築構法計画と建築生産

建築構法

建築の

  • 具体的にどのようなものか
  • 構成
  • 作り方

を決める。設計者が決める。工法との違いは?

  • 構法→建築のありよう
  • 工法→建築工事のやりよう

建築構法と建築生産

建築のライフサイクルを箇条書きで書いてみると

  • プロジェクトの企画
  • 設計
  • 施工
  • 維持管理
  • 更新
  • 解体
  • 破棄

という感じ。これらに関わる建築活動が建築生産である。

この中のうち、設計に関わるのが建築構法である。建築構法は建築生産の一部と言える。

主体構法

建築構法には建物を支える構造を決める主体構法と壁や屋根などの構法を決める各部構法がある。

主体構法の主要なものとしては木造、S造、RC造が挙げられる。

建設業(ゼネコン)と製造業の違い

ちなみにゼネコンとはGeneral Contractor:総合請負者のことでConstructor:建設者とは異なる。

単品受注である

建設業では発注者が設計者に注文し、設計者は設計図・仕様書を作成する。それを元に工事費が決まり、契約・施工が行われる。周辺環境、建物規模は注文ごとに異なるので、仕様・価格も注文ごとに異なる。そのため、発注者は注文の時点で価格を元に決めることはできない。

一方、製造業では市場調査が行われ、それを元に需要想定がされ、必要な技術開発がされ、完成した製品が大量生産される。消費者は出来上がった製品とあらかじめ定められた価格を購入の判断をすることができる。

屋外・移動生産である

建設業は屋外で生産し、屋外で完成させるため、自然条件の影響を受けやすい。また、ゼネコン1社が受け持つ現場は全国に広がる。

一方、製造業では限られた工場に材料が集められ、製品を生産し、出荷されるため、生産は限られた場所で屋内で行われることが多い。

総合組立産業・分業生産である

建設業はプロジェクトごとに材料・部品を調達し、材料そのものの生産は行わないため、価格変動に影響される。労働力に関してもプロジェクトごとに調達する。労働力の調達はゼネコンをトップとして重層構造で行われ、ゼネコンは専門工事業者(Sub-Contractor)に工事を委託する。委託を受けた専門工事業者はその元にプロジェクトごとに集められた技能労働者・技能作業者に委託する。これらの労働者はゼネコン社員ではなく、熟練を求められるような専門性の高い作業を行う。

建築生産の流れ

企画

基本的に発注者が行う。決められる内容としては

  • 用途
  • 規模
  • 機能
  • 予算

といったもの。これらは基本計画としてまとめられる。

設計

設計者が基本計画を元に設計図と仕様書をまとめる。流れとしては

  • 企画設計
  • 基本設計
  • 実施設計

の順に行われる。

工事費見積〜契約

設計図に基づいて工事費を見積もり、発注者との間で工事契約を結ぶ。

施工

狭義の建築生産で、主にゼネコン・サブコンが行う。施工図を作成し、協力業者を選定・指導し、品質、予算、工程、安全などの面から施工管理をする。

保全

ゼネコンや管理会社がメンテナンス・定期診断を行う。

設計の仕事

広義の建築生産のうち、設計の仕事についてフォーカスしてみる。

主な仕事は

  1. 図面の作成
  2. 仕様書の作成

の2つである。

企画・計画

設計者の立場から要求条件、建築の機能、法規制、敷地条件を整理する。

基本設計

企画・計画で決まった方針を元に基本設計図書を作成する。

基本設計図書は主に意匠・構造・設備の3つに分類され、以下のようなものがある。

  • 概要書
  • 一般書(平面図・立面図・断面図)
  • 詳細図(矩計図など)
  • 構造図
  • 設備図

これらを元にコスト検討を行う。

実施設計

施工者に設計内容を伝える図面の作成をする。

  • 実施設計図(平面図・立面図・断面図・各詳細図・建具リスト)
  • 仕様書(材料品質、施工方式等の指示)
  • 構造:軸組図、部材断面表
  • 設備:幹線系統図、各種設備図

などなど、膨大な量になる。

建築確認申請

法規への適合の条件のチェックをする。自治体(特定行政庁)または民間の指定確認検査機関に設計者より書類が提出され、チェックされる。

工事監理

工事管理とは異なり、作成した図面通りに工事が行われているかどうかを現場でチェックする。第三者が行う場合も設計者自身が行う場合もあるが、同一組織で行う場合、設計と監理の部署は明確に分離されている。

竣工図の作成

竣工図とは、実施設計後に変更になったことを反映した図面のことであり、設計者と施工者で分担して作成され、発注者にも渡される。

施工の仕事

施工管理は現場責任者(ゼネコンの工事事務所所長)、主任技術者、専門工事者によって行われる。

  • 工事の進め方の計画
  • 職人の統括・指揮
  • 発注者、設計者、工事監理者、関係官公庁、近隣住民、商社などとの折衝

キーワードとなるのは「Q・C・D・S・E」

  • Quality(品質)
  • Cost(工事費)
  • Delivery(工程)
  • Safety(安全)
  • Environment(環境)

建築生産の中での建築構法

以上で述べた手順のうち、設計の中で構法の知識が生かされる。施工の段階で用いられるのは工法の知識。

鉄骨造の構法

鋼材

鋼材の基本知識

大空間を構成するために古くから用いられてきた。鋼には以下の2種類がある。

  • 炭素鋼(普通鋼) Fe + C
  • 合金鋼(特殊鋼) Fe + C + Ni, Cr, Mn...

鋼材の性質

  • 軽量
  • 高強度
  • 靭性大
  • 不燃・非耐火→耐火被覆必要
  • 錆びやすい→防錆必要
  • 変形大

JIS規格では様々な鋼材の種類がある。

  • 建築構造用鋼材(SN)
  • 一般構造用鋼材(SS)
  • 溶接構造用鋼材(SM)

製造方法による分類

ほとんどの鋼材は圧延材と呼ばれる、鋼片を加熱し、圧し延ばして作られるものである。

  • 鋼板
  • 形鋼:規格化された断面を持つ。

さらに鋼板からは角形鋼管などが作られる。

鋼材の接合方法

  • 溶接
  • ボルト接合
  • リベット接合

の3つであるが、リベット接合は現在は使われていない。

溶接は、主にアーク溶接であり、アーク放電現象の熱を利用して 母材である鋼材と溶接棒の金属を分子レベルで接合する。施工条件に左右され、高い技量が求められる。母材の縁を切り出して間を溶接棒の金属で埋める突き合わせ溶接と母材の脇に溶接棒の金属をつける隅肉溶接の2種類があり、隅肉溶接の方が容易であるが、溶接部分の強度は劣る。

ボルト接合は一般に高力ボルト接合と呼ばれる、高力ボルトと呼ばれるボルトを用い、鋼材同士の摩擦力を利用した接合方法が用いられる。鋼材の穴端にボルトの軸が当たって、力を伝える方式は普通ボルト接合と呼ばれるが、この方式は緩み、がたができる。トルシア型高力ボルトと呼ばれるボルトもあり、締め付けが十分に達するとピンテールと呼ばれる部分が破断する、締め付けが容易なボルトである。

リベット接合は、熱したリベットの反対側をリベッターとよばれる工具で丸めて留める方法である。

躯体構法

ラーメン構造(純ラーメン構造・二方向ラーメン構造)

ラーメン構造とは柱と梁を剛接合で留めることで躯体とする構造方式のこと。

柱には角形鋼管や丸鋼管が用いられ、x・y方向に強さの違いがなく、ブレース(斜材)のない架構が可能であるため、開口などのプランの自由度が高い。

デッキプレートとよばれる波型の鋼板の上にコンクリートが打設され、スラブとなる。スタットボルトとよばれる梁鋼材から飛び出したボルトがコンクリートに埋め込まれ、スラブと梁が一体となる。

柱と梁の接合はブラケットとよばれる柱の端を一部切断して工場で柱にあらかじめ溶接したものと梁をスプライスプレートでボルト接合することで行われる。ブラケットと柱の結合にダイヤフラムとよばれる部材が用いられることが多く、

  • 外ダイヤフラム
  • 内ダイヤフラム
  • 通しダイヤフラム

の3種類がある。外・内ダイヤフラムはそれぞれ中空の柱の外側・内側に板を溶接するもので、通しダイヤフラムは柱を切断して柱の断面に板を通すものである。

柱脚部については以下の3種類がある。

  • 露出柱脚
  • 根巻き柱脚
  • 埋め込み柱脚

柱の根元にある板、ベースプレートと基礎に打ち込まれたアンカーボルトを接合する。露出柱脚では柱の根元をそのまま露出してピン接合とし、根巻き柱脚ではさらにコンクリートをかぶせることで剛接合とする。埋め込み柱脚では基礎部分に柱が埋め込まれる。

鉄鋼は不燃ではあるが、非耐火であるため耐火被膜が施される。モルタルに人口の鉱物繊維である、ロックウールを混ぜたものを吹き付けたり、ボード状やフェルト状のものをかぶせたりする。

一方向ラーメン構造(一方向ブレース構造)

純ラーメンでは柱に角形鋼管や丸鋼管が用いられたが、一方向ラーメンではH型鋼が用いられる。そのため、強軸方向と弱軸方向が生まれ、強軸方向を剛接合、弱軸方向をピン接合とする。純ラーメンと比較すると柱梁の接合が簡単で、鋼材が少なくてすむが、ブレースが必要となりやすいので、開口などのプランで制限を受けることになる。

梁をくの字にしたものを山形ラーメン構造と呼び、工場、倉庫、体育館などの大空間でよく用いられる。

トラス構造

平面トラスと立体トラスの2種類がある。接合が難しい分、軽量な鋼材で済む。

鋼管構造

鋼管で主体構造を構成するもので、断面が単純なため、自由な曲線を作り出せるが、接合の多くは溶接となってしまう。

張弦梁構造

アーチとなった弓とその端同士を結ぶ弦とそれらを繋げる束で構成される構造で、それぞれの曲げモーメントが打ち消しあって、強い構造となる。

軽量鉄構造

プレファブ建築として用いらることが多い。材料自身の重量が軽い。

屋根の構法

屋根構法の種類

傾斜のある屋根を勾配屋根、水平な屋根を陸屋根という。勾配屋根では木造同様、野地板の上に葺き材が敷かれる。後述するように野地板を用いない構法もある。

折板屋根

母屋の上に直接折板を敷く。

  • 重ね方式
  • はぜ方式
  • 嵌合方式
  • 二重方式

などがある。

重ね方式は折板同士を重ねて重なった部分をボルトで接合する方式。

はぜ方式は梁の上に取り付けたタイトフレームとよばれる金属具にはぜとよばれる折り込みで連なった折板を固定する方式。

嵌合方式はタイトフレームに固定した折板にキャップとよばれる固定具をはめる方式。

二重方式は折板を二重にして間に断熱材を入れる方式。

波板葺き

母屋に直接載せた波状の板をフックボルトという金物で留めたもの。剛性は低い。4枚の板が重ならないように内側の斜向かいの2枚の板を斜めに切り落とす。

陸屋根

端に立ち上がっている部分をパラペットという。上部を笠木とよばれる仕上げ材で覆う。パラペット部分は防水層を含んでいなければならない。

バルコニー・廊下・階段

デッキプレートにコンクリートを打設したり、押出成形セメント板とよばれる材料をそのまま用いて施工される。

外周壁の構法

カーテンウォール

構造躯体と異なり、建物に加わる力を負担しない壁のこと。カーテンウォールの外周壁を広義のカーテンウォールに含めることもある。狭義ではプレファブ化されたある程度の大きさを持つパネル型の部材でクレーンで外周壁に取り付けられるもののみを指す。

カーテンウォールの種類

材料によって分類すると

  • メタルカーテンウォール
  • プレキャストコンクリートカーテンウォール(PCaカーテンウォール)

構成方法によって分類すると

  • マリオン方式
  • スパンドレル方式
  • パネル組み合わせ方式
  • 柱・梁カバー方式

マリオン方式は上下の床・梁の間にマリオンとよばれる金属部材をかけ渡し、そこにパネルやガラスをはめ込む方式。

スパンドレル方式は床・梁の全面にパネルを取り付けその間に窓を横に連続してはめ込む方式。

パネル組み合わせ方式はパネルで壁を構成し、それを枠にして窓をはめ込む方式。

柱・梁カバー方式は柱・梁を包み込む形のパネルをはめ込み、それを枠にして窓をはめ込む方式。

カーテンウォールにおける層間変位追従のしくみ

躯体に固定され、水平移動するスウェイ方式と、躯体に対し回転するロッキング方式がある。

カーテンウォールにおける防水のしくみ

目地からの水の侵入を防ぎたい。目地を室外側、室内側の両方からシールするクローズドジョイント方式では定期的に交換が必要である。目地を完全には塞がず、室外と室内の気圧差をなくすことで水が侵入しにくくし、侵入しても外に排出するオープンジョイント方式はメンテナンスが必要ないため、高層ビルで広く用いられている。

ALC

Autoclaved Lightweight Concrete:軽量化気泡コンクリートのこと。軽量で、耐火性・吸水性があり、施工が容易。外周壁とする場合は層間変位追従にロッキング方式を採用するのが主流である。

押出成形セメント板

押し出し成形されたセメント板。オープンジョイントも可能である。

金属系サンドイッチパネル

鉄骨に断熱材と一体化した金属版を取り付けたもの。

開口部とグレージング

グレージング

Glazing:ガラスをはめ込むこと。

内装構法

オフィスビルの床構法

かつては配線は床スラブに埋め込まれており、レイアウトの変更に大きな制限がかかっていたが、現在はフリーアクセスフロアとよばれる内側に空間をもつ床材が用いられるようになった。主流な仕上げ材もプラスチックパネルからタイルカーペットへと変化している。

オフィスビルの壁・天井構法

亜鉛めっき鋼板の壁下地がポピュラーである。水平部材をランナー、鉛直部材をスタッド、スタッド間のスペースを確保する部材をスペーサー、スタッド同士を水平に繋ぐ部材を振れ止めと呼ぶ。

天井については、床スラブ・デッキプレートからボルトを吊り下げ、ボルト先のハンガーに野縁受けを吊り下げ、それに交差させて野縁を取り付ける。野縁に石膏ボードを取り付けて天井下地とする。吸音材としてロックウール吸音板をその上に張ることが多い。天井下地と天井仕上げ、天井設備が一体となったシステム天井というものも存在し、オフィスビルで多用される。ラインタイプとよばれる方式の天井ではTバーまたはHバーにCチャンネルをとりつけ、それに天井パネルを留める。

鉄筋コンクリート造の構法

材料

鉄筋コンクリートとは

Reicforced Concrete:RCのことで、鉄筋を組み立てたところにコンクリートを打設したもの。

コンクリートと鉄筋の性質

石灰石や粘土などを細かくして混ぜ、焼いたものをクリンカーと呼ぶ。これに石膏に混ぜて作ったものをセメントと言い、セメントと砂と水を混ぜたものをモルタル、さらに砂利まで加えたものをコンクリートと呼ぶ。

鉄筋はコンクリートの付着を大きくするために凹凸をつけた異形鉄筋と丸鋼があるが、丸鋼は今は使われていない。

鉄はコンクリートアルカリ性によって錆びないが、コンクリートは空気中の二酸化炭素などと反応して中性化するため、劣化が進むと鉄は錆びる。また、コンクリートは耐火性があるため、熱に弱い鉄を守る役割もある。一方、コンクリートは圧縮に強いが、引っ張りに弱いため、圧縮と引っ張りどちらも強い鉄筋で補強している。幸いなことにこれら2つの熱膨張率はほとんど等しい。

配筋

前述の通り、コンクリートは引っ張りを負担しないため、鉄筋の配置は建物が受ける力を負担しきれるよう行われる。原理的には引っ張り側に鉄筋を多く配置すればよい。継手にも種類があり、

  • 重ね継手
  • 溶接継手
  • ねじ継手
  • スリーブ重鎮継手

などがある。重ね継手は異形鉄筋では重ねるだけで、丸鋼ではフックが必要となる。ねじ継手は鉄筋側にねじ山が必要となる。スリーブ重鎮継手は鉄筋同士の接合部をスリーブと呼ばれる管で囲い、隙間をモルタルで埋めて接合するというもの。

型枠

コンクリートが固まるまでその形を固定する枠で、直接コンクリートを塞きとめる板をせき板、それを支える角材を端太、それを支える架構を支保工という。鉄筋がコンクリートの中心にくるよう指示する部品をスペーサーといい、鉄筋に取り付ける。打設後、脱型するものとしないもの(デッキプレートなど)があるが、使用した型枠を上方にスライドさせて再び使用するスライディングフォームというやり方もある。

種類としては

  • 合板
  • 木(木目がつく)
  • アルミ
  • プラスチック
  • 紙パイプ

などがある。

コンクリートの調合・打設

打設には流動性が必要であるが、その試験としてはスランプ試験が主流である。打設は型枠の隅々までコンクリートが行き渡ることが重要であり、バイブレータなどを用いて工夫されているが、コンクリートが行き渡らなかった部分はジャンカと呼ばれ、補修が必要となる。また、複数回に分けて打設を行なった場合、打設のブランク時間を短くしなければ、コンクリート同士がうまく一体化せず、コールドジョイントと呼ばれる継ぎ目ができてしまう。

躯体構法

RC壁式構造

構造材として壁と床を用いる構造。大規模空間は作れないが、経済的で内装が容易であり、耐震・耐火性に優れる。構造解析は複雑になるため、建築学会の定める設計基準に乗っ取って構造設計を行うのが一般的である。

RCラーメン構造

S造同様、柱梁を剛接合したもの。梁としては

  • あばら筋
  • 壁梁
  • ハンチ

などがある。あばら筋は軸方向に伸びた主筋に垂直に巻きつけた鉄筋のこと。壁梁は建物外周の梁を腰壁(窓下の壁)や小壁(窓上の壁)と一体化させたもの。ハンチは梁の柱付近の太さを傾斜をつけて太くしたもの。現在では梁の太さは端部を基準として一定に定められる。

柱におけるあばら筋は帯筋と呼ばれ、せん断耐力を高め、主筋の座屈を防止する役目を持っている。

プレストレストコンクリート構造、フラットスラブ構造

プレストレストコンクリートとはコンクリートの引っ張り側にあらかじめ圧縮力を加えておき、通常のコンクリートよりも耐力を高めたもの。圧縮力を加えるタイミングによって分類され、脱型前に力を解放する方式をプレテンション方式、脱型後に力を加え始める方式をポストテンション方式という。

フラットスラブ構造とはスラブを直接柱で支える構造で、スラブと梁が一体となった構造。スラブの厚さは柱梁構造よりも厚くする。

その他の構造

殻の面内応力で荷重を負担するシェル構造や、シェル構造を複数の平面で置き換えた折板構造などがある。高層建築でRCを用いる場合は高強度コンクリートが用いられる。

MerlinのDNNモデルを記述したコードの解説

概要

音声合成ツールMerlinのDNNモデルを記述したコードの解説。

Theano

学習を促すのはsrc/run_merlin.py151行目のtrain_DNNメソッド。その244行目での記述によるとモデルはsrc/models/deep_rnn.pyDeepRecurrentNetworkクラスによって生成される。
※名前に反してRNN以外の通常のDNNモデルもこのクラスによって生成される。

dnn_model = DeepRecurrentNetwork(n_in= n_ins, hidden_layer_size = hidden_layer_size, n_out = n_outs, L1_reg = l1_reg, L2_reg = l2_reg, hidden_layer_type = hidden_layer_type, output_type = cfg.output_layer_type, dropout_rate = dropout_rate, optimizer = cfg.optimizer, rnn_batch_training = cfg.rnn_batch_training)

まず、このクラスのコンストラクタ__init__src/model/deep_rnn.py28行目)において隠れ層、出力層、損失関数などについて記述されている。 configurationファイルのhidden_layer_typeは隠れ層の数とそれぞれの活性化関数を記述した項目で、tanhやlstmなどの文字列のリストが入る。この項目に沿ってsrc/layer内に記述される層が生成され、それらがリストで繋げられる。主にサポートしているのは下の5項目。
src/model/deep_rnn.py59行目

self.list_of_activations = ['TANH', 'SIGMOID', 'SOFTMAX', 'RELU', 'RESU']

この5項目に該当しない場合は個別に条件分岐する。
src/models/deep_rnn.py91行目

if hidden_layer_type[i] in self.list_of_activations:
    hidden_activation = hidden_layer_type[i].lower()
    hidden_layer = GeneralLayer(rng, layer_input, input_size, hidden_layer_size[i], activation=hidden_activation, p=self.dropout_rate, training=self.is_train)
elif hidden_layer_type[i] == 'TANH_LHUC':
    hidden_layer = SigmoidLayer_LHUC(rng, layer_input, input_size, hidden_layer_size[i], activation=T.tanh, p=self.dropout_rate, training=self.is_train)
elif hidden_layer_type[i] == 'SLSTM':
    hidden_layer = SimplifiedLstm(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'SGRU':
    hidden_layer = SimplifiedGRU(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'GRU':
    hidden_layer = GatedRecurrentUnit(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'LSTM_NFG':
    hidden_layer = LstmNFG(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_r
ate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'LSTM_NOG':
    hidden_layer = LstmNOG(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'LSTM_NIG':
    hidden_layer = LstmNIG(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'LSTM_NPH':
    hidden_layer = LstmNoPeepholes(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'LSTM':
    hidden_layer = VanillaLstm(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'BSLSTM':
    hidden_layer = BidirectionSLstm(rng, layer_input, input_size, hidden_layer_size[i], hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'BLSTM':
    hidden_layer = BidirectionLstm(rng, layer_input, input_size, hidden_layer_size[i], hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'RNN':
    hidden_layer = VanillaRNN(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
elif hidden_layer_type[i] == 'LSTM_LHUC':
    hidden_layer = VanillaLstm_LHUC(rng, layer_input, input_size, hidden_layer_size[i], p=self.dropout_rate, training=self.is_train, rnn_batch_training=self.rnn_batch_training)
else:
    logger.critical("This hidden layer type: %s is not supported right now! \n Please use one of the following: SLSTM, BSLSTM, TANH, SIGMOID\n" %(hidden_layer_type[i]))
    sys.exit(1)

かなり多くのパターンをサポートしていることが分かる。
出力層はlinearrecurrentと上のself.list_of_activationsリスト内の項目がサポートされている。
src/models/deep_rnn.py131行目

if output_activation == 'linear':
    self.final_layer = LinearLayer(rng, self.rnn_layers[-1].output, input_size, self.n_out)
elif output_activation == 'recurrent':
    self.final_layer = RecurrentOutputLayer(rng, self.rnn_layers[-1].output, input_size, self.n_out, rnn_batch_training=self.rnn_batch_training)
elif output_type.upper() in self.list_of_activations:
     self.final_layer = GeneralLayer(rng, self.rnn_layers[-1].output, input_size, self.n_out, activation=output_activation)
else:
    logger.critical("This output layer type: %s is not supported right now! \n Please use one of the following: LINEAR, BSLSTM\n" %(output_type))
    sys.exit(1)

これら出力層も隠れ層同様にsrc/layer内のファイルで記述されている。
損失関数はデフォルトで二乗誤差が設定されているが、全部で3種類サポートされている。 src/models/deep_rnn.py149行目

if self.loss_function == 'CCE':
    self.finetune_cost = self.categorical_crossentropy_loss(self.final_layer.output, self.y) 
    self.errors        = self.categorical_crossentropy_loss(self.final_layer.output, self.y) 
elif self.loss_function == 'Hinge':    
    self.finetune_cost = self.multiclass_hinge_loss(self.final_layer.output, self.y)
    self.errors        = self.multiclass_hinge_loss(self.final_layer.output, self.y)
elif self.loss_function == 'MMSE':
    if self.rnn_batch_training:
        self.y_mod = T.reshape(self.y, (-1, n_out))
        self.final_layer_output = T.reshape(self.final_layer.output, (-1, n_out))

        nonzero_rows = T.any(self.y_mod, 1).nonzero()
            
        self.y_mod = self.y_mod[nonzero_rows]
        self.final_layer_output = self.final_layer_output[nonzero_rows]
            
        self.finetune_cost = T.mean(T.sum((self.final_layer_output - self.y_mod) ** 2, axis=1))
        self.errors = T.mean(T.sum((self.final_layer_output - self.y_mod) ** 2, axis=1))
    else:
        self.finetune_cost = T.mean(T.sum((self.final_layer.output - self.y) ** 2, axis=1))
        self.errors = T.mean(T.sum((self.final_layer.output - self.y) ** 2, axis=1))

src/run_merlin.pyを見ると244行目でモデルを定義したのちに、284行目でbuild_finetune_functionメソッドを用いていることが分かる。このメソッドは、上のDeepRecurrentNetworkクラスのメソッドで、src/models/deep_rnn.py187行目に記述されている。損失関数を定義するメソッドであるが、以下のupdatesオプティマイザにあたり、メソッドを繰り返すたびに共有変数(T.share)を更新するアルゴリズムである。
src/models/deep_rnn.py248行目

train_model = theano.function(inputs = [lr, mom],  #index, batch_size
                              outputs = self.errors,
                              updates = updates,
                              givens = {self.x: train_set_x, #[index*batch_size:(index + 1)*batch_size]
                                        self.y: train_set_y,
                                        self.is_train: np.cast['int32'](1)}, on_unused_input='ignore')

ただ、build_finetune_functionという名前でありながら、どこでファインチューニングしているかがよく分からない。

TensorFlow

モデルの大枠はsrc/tensorflow_lib/models.pyに記述されており、実際の学習や予測の様子はsrc/tensorflow_lib/train.pyに記述されている。models.pyのクラスをtrain.pyのクラスが継承することで変数やメソッドを共有している。流れとしては以下の通り。
1 src/run_merlin.py816行目でsrc/run_tensorflow_with_merlin_io.pyのオブジェクト生成、850行目でそれにモデル定義・学習を指示する。

elif cfg.switch_to_tensorflow:
    ### call Tensorflowclass and use an instance ###
    from run_tensorflow_with_merlin_io import TensorflowClass
    tf_instance = TensorflowClass(cfg)
elif cfg.switch_to_tensorflow:
    tf_instance.train_tensorflow_model()

2 src/run_tensorflow_with_merlin_io.py148行目でsrc/tensorflow_lib/train.pyのオブジェクト生成、182行目でそれにモデル定義を指示、195行目でそれにモデル学習を指示する。

if not self.encoder_decoder:
    self.tensorflow_models = TrainTensorflowModels(self.inp_dim, self.hidden_layer_size, self.out_dim, self.hidden_layer_type, self.model_dir, output_type=self.output_layer_type, dropout_rate=self.dropout_rate, loss_function=self.loss_function, optimizer=self.optimizer)
else:
    self.encoder_decoder_models = Train_Encoder_Decoder_Models(self.inp_dim,self.hidden_layer_size,self.out_dim,self.hidden_layer_type,output_type=self.output_layer_type, dropout_rate=self.dropout_rate,loss_function=self.loss_function,optimizer=self.optimizer, attention=self.attention,cbhg=self.cbhg)
#### define the model ####
if self.sequential_training:
    utt_length=train_flen["utt2framenum"].values()
    self.tensorflow_models.get_max_step(max(utt_length))
    self.tensorflow_models.define_sequence_model()

elif self.encoder_decoder:
    utt_length=train_flen["utt2framenum"].values()
    super(Train_Encoder_Decoder_Models,self.encoder_decoder_models).__setattr__("max_step",max(utt_length))
    self.encoder_decoder_models.define_encoder_decoder()
else:
    self.tensorflow_models.define_feedforward_model()
#### train the model ####
print('training...')
if self.sequential_training:
    ### Train feedforward model ###
    self.tensorflow_models.train_sequence_model(train_x, train_y, batch_size=self.batch_size, num_of_epochs=self.num_of_epochs, shuffle_data=self.shuffle_data,utt_length=utt_length)

elif self.encoder_decoder:
            
self.encoder_decoder_models.train_encoder_decoder_model(train_x,train_y,batch_size=self.batch_size,num_of_epochs=self.num_of_epochs,shuffle_data=True,utt_length=utt_length)
else:
    self.tensorflow_models.train_feedforward_model(train_x, train_y, batch_size=self.batch_size, num_of_epochs=self.num_of_epochs, shuffle_data=self.shuffle_data)

3 src/tensorflow_lib/train.pysrc/tensorflow_lib/train.pyのクラスはsrc/tensorflow_lib/model.pyのクラスを継承したもの。src/tensorflow_lib/model.pyのメソッドでモデルを定義、src/tensorflow_lib/train.pyのメソッドで学習を行う。モデルの種類によって実行するメソッドが変わってくる。

統計的音声合成について(HMM音声合成)

https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/44312.pdf
上のスライドを文章としてまとめたもの。まずは前半部分のHMM音声合成について。

人間の発声の仕組み

下の図は同スライドから引用した発声の仕組みについての図である。

f:id:k17trpsynth:20180309125858p:plain

人間は発声する際、咽頭で音源を作り出し、声道でその音源を共鳴させて音色を変えるという手順を踏んでいる。咽頭では声の強さ、声の高さ、有声音・無声音の切り替えなどが決定される。この時点では音源はブザーと同じであり、何の言葉を発しているかは分からない。そのブザーが声道で共鳴されることで初めて言葉として分かるものになる。声道の形を変えることで様々な種類の言葉を発している。

この人間の発声システムをコンピューター上で模倣できれば音声合成ができるはずである。システムを数学的に扱いやすくなるようにモデル化したものが同スライドから引用した下の図にあるソースフィルターモデルである。

f:id:k17trpsynth:20180309132221p:plain

Source excitation partが咽頭にあたり、Vocal tract resonance partが声道にあたる。咽頭における有声・無声の切り替えはスイッチで表現され、咽頭で発せられた音源(e(n))が声道フィルター(h(n))にかけられて声(x(n))になる様子が畳み込み積分(*)で表現されている。

x(n)=h(n)*e(n)をフーリエ変換したX(z)はh(n)、e(n)をそれぞれフーリエ変換したH(z)、E(z)の積H(z)E(z)となることが知られている(下図も同スライドの引用)。

f:id:k17trpsynth:20180309135304p:plain

ブザーのスペクトルE(z)は平坦な形をしているが、それにH(z)をかけて一部の周波数が強調されたりすることで、意味の分かる音声スペクトルX(z)となる。

HMM音声合成の手順

同スライドから引用した以下の図がHMM音声合成の手順である。

f:id:k17trpsynth:20180309104415p:plain

以下これに沿って説明していく。

HMM音声合成の手順:学習部(Training part)

音声データベースからパラメータを抽出

音声データから特徴量を抽出することは上で述べた発声システムを逆に追っていくことになる。咽頭の部分で Excitation parameter (基本周波数など)が、声道の部分で Spectral parameter (メルケプストラムなど)が抽出される。

HMMモデルの学習

コンテキストラベルと上で得られた音響特徴量をHMMに与えてモデルの学習を行う。まず、コンテキストに依存するHMMをつくるために決定木をもとにした分類を各状態に対し行う。各状態のコンテキストラベルに対してイエスかノーで答えられる質問をいくつか与え、クラスに分類し、それぞれでモデルを学習する。この質問は Excitation parameter と Spectral parameter で別々に用意され、継続長モデルにも個別に用意される。同スライドから図を引用する。

f:id:k17trpsynth:20180316114058p:plain

HMMにおける潜在変数はこの各クラスにあたり、出力変数は各音響特徴量または継続長である。コンテキストがあるクラスに分類されることを条件とした出力変数の条件付き確率分布を学習する。

継続長モデルの学習の仕組みは「ある状態に時間t0で遷移し、その後の時間t1で抜ける確率」を各t0、t1に対して計算するというもの。

HMM音声合成の手順:合成部(Synthesis part)

言語特徴量からパラメータを予測

合成用テキストから得たコンテキストラベルをHMMに与え、もっともらしいパラメータを抽出する。同時にその確率分布の分散と動的特徴量も得て、これらを考慮して最終的に時系列に沿って滑らかなパラメータを得る。

パラメータから波形の合成

HMMから得たパラメータを冒頭で述べた人間の発話の仕組みに沿って波形として合成する。パラメータから波形に変換する際に用いられるフィルターはパラメータの種類ごとに用意されている。代表的なものとしてはメルケプストラムを変換するMLSAフィルタなどがある。

応用的なHMMの話題

話者適応

様々な話者の声を学習した平均声モデルを作り、目標話者の声を作成する際に必要とするデータ量を最小限にするというもの。少ないコストで新しい声の合成ができる。

パラメータ抽出時の問題

  • 有声か無声かを1か0かで判定していると、有声音と無声音の混ざった音はパラメータ抽出しづらい。
    →対策として有声音・無声音それぞれをバンドパスフィルタにかけて混合するという手法がある。(同スライドから引用)
f:id:k17trpsynth:20180316143332p:plain
  • 状態内での確率分布が一定。 出力確率分布が各状態ごとに独立ではないかもしれない。
    →対策として静的・動的特徴量の関係を明示化した Trajectory HMM などが用いられている。

  • 継続長モデルが弱い。
    →対策として継続長を明示した隠れセミマルコフモデルが用いられている。

  • 動的特徴量を考慮してパラメータ出力することで滑らかなパラメータが生成されるが、スペクトルの細かい部分が省略されてしまうため、しばしば過剰に平滑化され、こもって聞こえる。
    →対策としてポストフィルタ、GVなどが用いられる。

参考

https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/44312.pdf
音源フィルタ理論
ソースフィルタモデルについてのまとめ(永遠に未完) - 備忘録
http://tanichu.com/wp-content/themes/tanichu/data/pdf/ess12_kobayashi.pdf

MerlinのTensorFlowDNN構造まとめ

目的

音声合成ツールMerlinのTensorFlow使用時のデフォルトのDNNの構造を調べる。

方法

logに構造に関することが吐き出されていなかったのでTensorFlowコードとconfigファイルを直接確認した。src/tensorflow_lib/train.pyegs/slt_arctic/s1/conf/にあるconfigファイルを参照した。

結果

デモ フル
隠れ層数 4 6
隠れ層ユニット数 全て512 全て1024
隠れ層活性化関数 全てtanh 全てtanh
出力層活性化関数 線形 線形
オプティマイザ Adam法 Adam法
損失関数 2乗誤差 2乗誤差
バッチサイズ 256 256
ドロップアウト × ×
RNN × ×

ただしこれらは比較的容易に変更できる。

MerlinのデモスクリプトをTensorFlowを用いて実行してみる

目的

音声合成ツールMerlinのデモスクリプトをTensorlFlowを用いる方法で実行する。

方法

configurationの設定にswitch_to_tensorflowがある。デフォルトでFalseになっているのでこれをTrueに変更したい。
egs/slt_arctic/s1/script/にあるprepare_config_files.shの継続長モデル設定ファイル(duration_config_file)の[Architecture]の項目に以下のように追記する。

$SED -i s#'switch_to_tensorflow\s*:.*'#'switch_to_tensorflow: True'# $duration_config_file

音響モデル設定ファイル(acoustic_config_file)の[Architecture]の項目にも同様に追記する。上の$duration_config_file$acoustic_config_fileに変えるだけで良い。また、prepare_config_files_for_synthesis.shにも同様にacoustic_config_file、duration_config_file共に追記する。

以上の追記を行うと02_prepare_config_files.shを実行して生成されるconfigファイルのswitch_to_tensorflowTrueになる。

なぜかsrc/tensorflow_lib/内のファイルはPython3.xをサポートしていない(他のディレクトリはサポートしているのにも関わらず)。そのため、Python3.xを使用している場合、そのままモデルの学習を行おうとするとエラーが出る。この場合、2to3コマンドを用いてディレクトリ内のファイルを全て書き換えるなどする必要がある。

以上の工夫を施すとデモスクリプトをTensorFlowを用いて実行することができる。

デモで学習ファイル数やepoch数が少なく判断しかねるが、生成された音声はTensorFlowを使用しない時と比較してこもったように聞こえ、質が悪くなったように感じた。

Merlinが音響特徴量から波形を合成する過程について

目的

音声合成ツールのMerlinを動かす際の、ニューラルネットワークを用いて推定した音響特徴量から音声波形を合成する過程を調べる。

まずconfigについて

  • 変数の設定についてはsrc/configuration/configuration.py内に書かれており、クラス内メソッドのうち、主にuser_configurationメソッド内のリストuser_optionsで変数のデフォルトがインスタンス変数として指定され、引数として指定したconfigファイルでそれが上書きされる。つまり、デフォルトの値よりもegs/slt_arctic/s1/conf/test_synth_jsut_full.confの値が優先される。

本題:音響特徴量から波形になるまでの過程について

  • 記事(DNN統計的音声合成ツールキット Merlin の中身を理解をする - LESS IS MORE)にもあるように、波形合成をする前に得られた静的特徴量と動的特徴量から、MLPGアルゴリズムと呼ばれるもので特徴量を計算し直している。この特徴量の次元は静的特徴量の次元に等しい(次元数は3分の1になる)。MLPGアルゴリズムの内容は隠しファイルsrc/frontend/.mlpg_fast.pyに書かれている。

  • egs/jsut/s1/conf/内のtest_synth_jsut_full.confの設定のうち、vocoder_typeを確認すると、波形合成のVocoderにはWORLDが用いられていることが分かる。
    具体的な波形合成のコードはsrc/utils/generate.pyに書いてあるが、VocoderにWORLDを用いる場合、そのうちのwavgen_straight_type_vocoderメソッドが実行される。このメソッド内でSPTKと WORLDを動かして音声波形を作っている。

  • wavgen_straight_type_vocoderメソッドでは、まずメルケプストラムにポストフィルターと呼ばれるものがかけられる。その手順は同ファイル内のpost_filterメソッドに書かれている。フィルターをかけられた後のデータが拡張子.mgc_p_mgcを持つものである。

  • その後で波形合成が行われる。流れは以下の通り。最後以外はSPTK。

    • 対数f0をf0に変換。その際、0の代わりに用いられた微小量は0に置き換えられている。その後にf0の文字型をfloatからdoubleに変換。
    • 非周期性指標が正の場合、値を0に置き換え。その後、文字型をfloatからdoubleに変換。
    • メルケプストラムをケプストラムに変換し、その複素数平面上での偏角を度数法で表す。この際、configファイルで見られる変数fw_alphaflをパラメータとして用いる。その値を32768(8進法で100000だが値の理由は不明)で割ったのちに2乗する。その後に文字型をfloatからdoubleに変換する。
    • 以上の変換されたデータを引数に指定してWORLDのSYNTHESISコマンドで波形合成。この際、configファイルで見られる変数flsrをパラメータとして用いる。

参考

DNN統計的音声合成ツールキット Merlin の中身を理解をする - LESS IS MORE

TensorFlowの変数を再利用できるように

問題

k17trpsynth.hatenablog.com

上の記事にて問題となっていたことが解決したので執筆。LSTMに学習をさせた後、同じコード上で予測をさせたり、同じコード上で続けて予測をさせたりすると以下のエラーが出るのであった。

NotFoundError (see above for traceback): Key Variable_4 not found in checkpoint
     [[Node: save_1/RestoreV2_4 = RestoreV2[dtypes=[DT_DOUBLE], _device="/job:localhost/replica:0/task:0/device:CPU:0"](_arg_save_1/Const_0_0, save_1/RestoreV2_4/tensor_names, save_1/RestoreV2_4/shape_and_slices)]]

原因

当時はこのVariable_4がcell内の変数を表しているのかと思っていた。

しかし、これは前利用した時と区別するために新しく名前がつけられているだけで、重み(w)とバイアス(b)であった。

つまり、エラーの原因は以下の通り。
1. 二度目の実行時に変数を再び定義するが、同じコード上でこれを行うと一度目の実行時に定義した変数と区別するために一度目とは違う名前がつけられる。
2. セッションを開始し、tf.Saver().loadで前回の学習で保存されたモデルの変数を復元する。
3. 保存された時とは違う名前の変数を要求され、怒られる。

解決法

これを直すためには二度目の実行時にも同じ名前で変数を定義できるようにしなければならない。
ただ、以下のようなコードで変数を定義してたが、tf.Variableでは変数を同じ名前で再利用する許可ができない(と思われる)。

w_hidden = tf.Variable(tf.random_normal([self.input_layer_size, self.hidden_layer_size], dtype="float64"))
b_hidden = tf.Variable(tf.random_normal([self.hidden_layer_size], dtype="float64"))
w_output = tf.Variable(tf.random_normal([self.hidden_layer_size, self.output_layer_size], dtype="float64"))
b_output = tf.Variable(tf.random_normal([self.output_layer_size], dtype="float64"))

そこで、上の部分をtf.variable_scopetf.get_variableを用いて以下のように書き換えた。

def make_weight_and_bias(scope_name, former_layer_size, latter_layer_size):
    with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE):
        w_init = tf.random_normal([former_layer_size, latter_layer_size], dtype="float64")
        b_init = tf.random_normal([latter_layer_size], dtype="float64")
        w = tf.get_variable("w", initializer=w_init, dtype="float64")
        b = tf.get_variable("b", initializer=b_init, dtype="float64")
        return w, b

w_hidden, b_hidden = make_weight_and_bias("hidden_variable_scope", self.input_layer_size, self.hidden_layer_size)
w_output, b_output = make_weight_and_bias("output_variable_scope", self.hidden_layer_size, self.output_layer_size)

tf.variable_scopeにはオプションreuseがあるのでこれをtf.AUTO_REUSEとすることで同じ名前で変数を再利用することを許可する。

以上の工夫を施した結果、エラーは解決した。