とある人類

書きたいことがあるときに書き残すログ

明治大学 総合数理学部 先端メディアサイエンス学科【卒業してみた】

こういう記事を書くと、どうしても「いや、それは違う」とか、怖い人に言われてしまう気がする。
しかし、せっかく1期生として大学に通い、留年することなく卒業できたのだから、なにかしらその過程で感じたものを残しておきたい。
それが誰かの役に立つか立たないかはさておき、あくまで個人の感想と「もし自分がもう一度入学したらこうしたい」くらいの感覚で。

はじめに


2013年に明治大学で ”総合数理学部” という学部が新たに設立された。
僕はその年、1期生として総合数理学部の先端メディアサイエンス学科(以下FMS)に入学し、2018年現在、同大学の大学院に在籍している。
僕が大学を卒業したのは2017年のことで、すでに1年が経過しようとしており、春には6期生が入学してこようとしている。

そこで(一応)現在在学しているFMS生に向けて、また今後入学してくる新入生に向けて「この学科を卒業するまでと卒業したあと」を、第1期の卒業生の立場からまとめておきたいと思う。
あくまで、一個人の見解を含むという前提で読んでいただければ幸いだ。
また本稿では、FMSに入学することについてはあまり取り上げていないので、あしからず。

そもそも大学を卒業するには


まずは、大学を卒業するにはどうしたらいいのかを知らない人向けに、それらのシステムについて一応簡単に説明しておきたい。
もう知っているという方は、本項は読み飛ばし次の項まで進んでいただきたい。

さて、大学に入学している時点でおそらく1度は、卒業というものを体験したことがあるのではないかと思う。
中学や高校であれば、学期ごとのテストの点数が成績として反映され、あまりにもひどくない限り(ちゃんと登校していれば)卒業できることだろう。
では、大学ではどうだろうか。

・基本的なシステムは同じ

大学も中学や高校と同様、それぞれの授業ごとに成績の評価が決定する。
評価は、S, A, B, Cの合格とFの不合格による5段階で行われる。
合格最低ラインとなるC判定は、成績のスコアが60点以上(100点満点中)となっており、それを下回るもの(60点未満)の場合はF判定となる。
6割もとらないと合格判定がもらえないのかと驚くかもしれないが、実際のところそれほど難しいことではない。

・評価方法は授業によってさまざま

大学の授業における成績評価は、中学や高校のようなペーパーテストであるとは限らない
例えば、実験に対する考察などをレポートの形式で書かせ、その内容で評価する場合がある。
他にも、プログラミングのような授業であれば、実際に作った制作物に対して評価する場合もある。
一方でもちろん、数学系の授業であれば、ペーパーテストによって評価する授業もあるし、いくつかの評価方法を組み合わせている(課題50%, テスト50%のような)場合もある。
このようにそれぞれの授業によって、その担当の教員が定めた評価の方法があるため、これまでのようにテスト勉強をしていれば大丈夫と一概には言えない。

しかし、これはむしろ好都合であるといえる。
中学や高校では、ほとんどの授業のテストが決められた期間の中で行われ、毎日のようにその勉強に追われることもあっただろう。
けれど評価方法がばらけたことによって、テスト期間中に行われるテストの数は明らかに減った
その分レポートやプログラミングの課題があるが、それらは決められた期限までに出せばいいので、自分の裁量で調節することが可能である
もちろんギリギリまでやらなければ、密集した提出期限によって過酷なスケジュールを強いられることになるのだが……。

ちなみに、出席数については大学でも重要になってくる。
出席をとらない授業もあるが、何かしらの方法でとっている場合の方が多いように思う。
とり方は出席表、小テスト、小課題提出など様々である。
この出席数であるが、学期中の授業実施回数の3分の1(おおよそ5回)を欠席すると、自動的にF(不合格)となるので注意が必要だ。

・大学の卒業判定は単位制

もしもテストの点数が悪かったり、課題の提出が間に合わなかったり、出席数が足りていなくても、どうか焦らないでいただきたい。
なぜなら、大学の卒業判定は単位制であるからだ。
単位というのは、成績の合格判定によって与えられる一定の数値であり、大学の卒業ではこの数値を規定数取得していることが条件となる。
なので、不合格判定をもらったからといって、そこで大学生活が終了してしまうわけではない。
では不合格判定をもらうとは、どういうことなのか。

不合格判定をもらうことを一般的に単位を落とす(落単)と言う。
単位を落とすことによって発生する問題には、次のようなものがある。
・合計取得単位数が増えない
・必修の授業の場合は次年度に再度履修
・GPAの数値が下がる

まずもちろんだが、取得した単位数の合計が増えない。
先ほども述べたが、卒業には決められた単位数が必要となってくるので、合計取得単位数が増えないと困る。
しかし、あくまでこの合計というのは卒業時(3年への進級時)に参照されるものなので、焦ってとりまくる必要はない。 だいたいの人がおそらく3年終了時にはこの単位数に達している(ゼミの単位を除く)ので、それくらいのペースで取得していけば問題ないだろう。

次に、必修の授業で単位を落とした場合だが、これは少し面倒である。
大学では、自分で選べる授業(選択)とあらかじめ決められた授業(必修)がある。
このうち必修の単位は、取得していなければ卒業できない単位であり、次年度以降に再度授業を受けて取得しなければならない。
1度受けたことのある授業をまた受けなければならないというのは、面倒なことであるし時間の無駄でもある。
あらかじめ必修の授業であるかどうかはわかっているので、選択よりもこちらに力を注ぐのが懸命とも言える。
もちろん、どちらの単位も取得しフル単(学期中に履修している授業の単位を全て取得した状態)であることに越したことはない。

最後に、GPA(成績評価値)が下がってしまうことが挙げられる。
GPA自体は、特定の計算によって求められた成績評価値であるが、FMSではこの数値を用いる機会がある。
それが、研究室の配属だ。
FMSでは1年次から研究室に配属(ランダム)され、2年次からは自身の希望する研究室に配属されることになる。
この際に配属先が定員を越した場合、GPAの数値が高い順(3年次には面談による場合もある)に配属されていくこととなる。
つまりGPAが下がることによって、後々の研究室配属において、自身の希望する研究室に配属されない可能性が大きくなってくる。
FMSの教員はどなたも魅力的ではあるが、しかしやはり、自身の興味や方向性のあった研究室へ進むに越したことはない。

このように、大学では取得した単位数によって卒業の可否が決まってくる。
なので「まあなんとかなるだろう」と課題提出が遅れたり、欠席回数が4回みたいなことをするのは危険である(というか僕がそれで死にかけた)。
実際にFMS内でも単位数が足りずに卒業できないという人も意外にいる(友人にも何人かいる)ため、安易な楽観視はおすすめできない。
最低限すべきことをこなしつつ、大学生活を満喫するのが賢明だろう。

FMSを卒業するまでと卒業したあと


さて、大学を卒業するためのシステムはわかっていただけただろう。
ここからは、FMSを卒業するまでと卒業したあとについて考えたい。
というかまあたぶん、この項はほとんど個人的な見解であると思う。

・FMSでの学生生活

まず思うに、FMSを卒業しようが、理工学部を卒業しようが、はたまた東大や東工大の学部を卒業しようが、それほど一個人にとっての違いはないのではないだろうか。
つまり、大学生活を通して学び取るものは個人の意欲に相対するものであり、環境はそれを育むためのファームにすぎない。
そして、FMSの教員は知識も経験も実績もある、言うなれば上質な肥料であり、育つために必要なものは十分に用意されているのだ。
その中で自分がどう成長するかを決めるのは、個人の問題である。
だから、FMSに入ったからといってなにかができるようになるわけではない
では、どうやって過ごすことが有意義なのだろうか。

まず1年次は、多くの物事に興味を持ってみるのがいいと僕は思う。
きっと、明確に何がしたいと決めてから入って来ている人は、そう多くはないのではないだろうか。
なんとなく面白そうとか、これに興味があるとか、そういう大雑把な感覚の人もいると思う。
そうして実際に入ってみて、様々なものに触れていく過程で、多くのものに感化される。
そうやって興味を持ったものに手を出し、挑戦してみることで徐々にやりたいことが明確化されていく。
それが最初の1年目であると考える。
しかしこれは単純に、プログラミングやVRやに興味を持てということではない。
学業に関係しなくても、それがサークルであれ、バイトであれ、まずは多くのものに触れることが大切なのだ。
「自分の興味の引き出しに詰め込めるだけ詰め込むこと」
これに尽きる。

そして2年次になったら、この引き出しの中のものを取り出す作業にかかる。
雑多な興味の中には、手を出してみたが合わなかったものや、まだ手を出せていないものも多くあるだろう。
そういったものを選り分けて、自分がこれだと思えるものを見つける作業にかかる。
このとき、見つけるための手がかりとして、就活のエントリーシートが参考になるのではないだろうか。
つまり「学生時代、あなたが最も力を入れて取り組んだことはなんですか」である。
それが継続してやってきたことであれ、新規に取り組むことであれ、残りの学生生活で最も力を入れて取り組みたいと思えること。
それがきっと理想形だ。

こうして3年次には、取り組みたいことに取り組める環境に身を置く
研究室選びも考える必要が出てくるかもしれない。
興味のある分野で研究したいなら、それが専門の教員の元に行くのがいいだろう。
あるいは、研究よりも興味のあることなどに力を入れたいのであれば、あまり研究を第一とするところは向かないだろう。
僕のいた研究室は、どちらかといえば後者だったので、研究と取り組みたいことのバランスがとりやすかった。
もし、学会やそれに類する出し物に積極的な研究室に行っていたら、自分はすぐ音をあげていただろうと思う。
こういったワークバランスみたいなものは、意外と大切に感じる
あとは、自身の性格面などとの兼ね合いを考えればいいだろう。

そうこうしてると4年次になり、就活や卒業研究に取り組むことになる。
この学年では、その先の進路を考えた行動が必要となってくる。
もし就職するのであれば、就活をして、これまでに力を入れてきた内容について存分に発揮すればいいだろう。
もし大学院に進学するのであれば、卒業研究としてではなく、その先に続けていけるような視点で研究に取り組むことも必要だろう。
ここで「大学院には進学できないから就活する」「就活したくないから大学院に進学する」といった考えで進路を選択すると、あとあと苦労することがあるかもしれないので、明確な理由を持って方向性を固めておいた方がいい。

・卒業後の進路としての就職

FMSの1期生の就職率(2016年度)は63.5%である。
1期生はだいたい200人程度だったので、130人近くは就職したことになる。
一方で大学院進学(院進)率は34.7%なので、70人近くとなっている。

僕自身は院進組なので、就活に関して詳しいわけではないが、同期の就活生を見ていたり、話していたりしてわかることもある。

まず、何も考えず「まあとりあえずSE(システムエンジニア)かな」みたいな人がいる。
情報系の学科だから何かしら活かせるだろうとか、仕事の方向性が合ってるんじゃないだろうかとか、たぶんそういう感覚なのではないだろうか。
あるいは、やりたい仕事がまだ決まっていなくて、周りが行こうとしてる業種に合わせただけかもしれないが。
そもそも、こういう人の中にはSEが何をする職種なのかわかっていない(他の職種と一緒くたになって、理系の総合職のような扱いの)人もいたように思う。
僕としては、この「まあとりあえず」みたいな感覚は捨ててしまっていいと考えている。
情報系だから、理系だから、みたいな理由でSEを希望しなければならない訳などないのだから。

実際のところ、FMS生は様々な職種に就職しているのではないだろうか。
もちろんSEもいるし、プログラマーやCGデザイナーのような専門的な技術職や、営業やコンサルタントのような文系職の人もいる。
そして概ね、それぞれの職種は学生生活の送り方や個人の人間性などを反映したものであるように感じる。
このうち特に、専門的な技術職においては、前述の学生生活で見出した興味が反映されている場合が多いのではないだろうか。
例えば、プログラミングに取り組んでいたならばプログラマーになったり、モデリングに取り組んでいたならばCGデザイナーになったり、動画制作に取り組んでいたならば動画クリエイターになったりと。
このように、学生生活で最も力を入れて取り組みたいと思えることを見つけ育むことは、きっと就職する際に自分のステータスとして有利に働いてくるのだろう。

ちなみに就活するにあたって、僕の身の回りだけかもしれないが「プログラミングはしたくない」と言っている人が意外にも多かった。
そう考えると、4年間授業などでプログラミングをしてきたからと言って、プログラマーになりたいという人は、割合少ないのかもしれない。

・卒業後の進路としての院進(博士前期課程)

改めての確認となるが、院進率は34.7%となっており、およそ70人程度が大学院に進学していることになる。
1期生は他の学年に比べ人数が多かったので、次の年からはだいたい35人程度が進学すると予測される。
この割合が実際のところ多いのか少ないのかは判断しかねるが、私立の大学院ではたぶん平均ぐらいだろうと思う。
国立の大学院であれば進学率は比較的高いらしいが、私立は支払う学費や支給される研究費の金額などから、進学に対して意欲的になれない場合も多いようだ。
では実際、大学院に進学することでどのようなメリットやデメリットがあるのだろうか。

まずは、あえてデメリットから述べたい。
デメリットとしては、私立の大学院の学費はそれなりにかかることが挙げられる。
僕の場合、2年間で200万円ちょっとくらいであり、学生の身で年間100万円を捻出するのは大変苦しい。
ある程度裕福な家庭であれば、親が学費を払ってくれるかもしれないが、そうではない学生も多い。
実際、奨学金によって学費をまかなっている大学院生もいるだろうが、昨今奨学金で破産などという話を聞くと、安易に借金を抱えるわけにもいかないだろう。
こういった金銭の問題は結構ネックである。
一方で研究費についてだが、これまでにあまり大きいプロジェクトに関わってこなかったからか、あるいは担当教員によるマネジメントが素晴らしいのか、それほど融通が効かないような思いをしたことはない。
また、学費の他にデメリットを感じる機会もあまりないように思う。

次に、メリットについて述べたい。
メリットとしては、自身の興味がある分野の専門性を高められることが挙げられる。
授業の形態は、論文の輪講や少人数を生かした密な講義などであり、授業数自体はそれほど多くない。
なので、授業によって今まで手に取ってなかった論文を読む機会も増えるし、講義では学部とは違った専門的な内容に触れることができ、それ以外の時間は自身の研究を進めることができる。
また、授業は完全に選択制なので、自身の研究に直結するものや、進展の足がかりとなるものを選んで受けることができる。
このような環境は、研究に興味を見出した人であれば魅力的であるし、有益に用いることもできるだろう。
それにせっかく高い学費を払っているのだから、教員に200万の投資をさせられるような研究へと取り組んで行きたいものである。
もし興味が研究以外の人であっても、2年間という時間的猶予を手に入れたのだから、その中でいくらでも興味の対象を育むことができるだろう。

ちなみに、大学院での過ごし方はピンからきりである。
例えば、学会や研究会へ積極的に参加し、自身の研究でも登壇による発表をこなす人もいれば、いつも自分の趣味ばかりに時間を費やしている人もいる。
一概にどちらが良い悪いという話ではないが、時は金なりであるし、実際にいくらか支払っているのだから、そうやって手に入れた時間や環境というものは、自身の納得がいくように有効的に使いたいものである。

まとめ


ようやくまとめに入る。
ここまで書いてみて思うに、案外どこの大学でも言えそうなことしか書いてないような気がしている。
結局は、個人の意思の問題だというのもあるだろう。
最後にいくつか、個人的な意見を述べたいと思う。

まず、1年生の段階で数年後には就活がある、という意識を持っておいた方がいい
ほとんどの人が就職するだろうし、そのために就活することになるだろう。
しかし、いざ就活がはじまってみると自己PRや頑張ったことといった内容は、意外に書けないものである。
なので、いつかはそういうものを書く機会が来る程度に意識しておくと、これは書けそうだといった事柄がストックとしてたまるのではないだろうか。

次に、学生であるからと言って、自己投資は惜しまない方がいい
実際、専門の技術職などだとAdobeといった高価なソフトを用いる場合もある。
もし、興味の内容がこういったソフトを必要とするものなのであれば、思い切って買った方がいいと思う。
あるいは、処理を要求されるのであれば、高スペックなパソコンを思い切って買った方がいいと思う。
使いこなせばより高度なものが作れるし、購入したからには使わなければといった感覚にもなるだろう。
こういった自己投資は、最終的にプラスとなって返ってくることが多いように感じる。

最後に、なんども言うがこれらは個人の見解であって、1年次からなにかに専門的に取り組もうが、4年次まで何もせずただ大学に通おうが、それはすべて個人の自由である。
FMSの環境では、どの学年から何を始めようと手遅れといったことはないし、積極的な学生は歓迎され、実績を残すための場も提供してもらえるだろう。
あくまでこの記事は、平凡な僕が「わかりやすく段階立てた大学生活を過ごしたかった」という希望を書いたものなのである。

あしからず。

ProcessingからPythonを実行したかった話

先日、とある機械学習をするのに画像データがある程度必要になったので、何か適当に画像を抜き取ってくる方法はないものかと探していました。

まぁ勝手にGo○gleさんの画像検索をスクレイピングして抜き出せばいいかなとか思っていたのだけれど、どうも規約違反らしいとのこと。 かと言って、他の画像検索サイトもおそらくグレーゾーンだろうと思ったので、それ用のAPI系を調べて見たけどどれも微妙……。

とりあえず今回はそれほど画像枚数はいらないのと、クエリに対して画像が返ってくるものがよかったので、G○ogleのcustom search apiを無料版で使ってみることに。

#! /usr/bin/python
# -*- coding:utf-8 -*-

import urllib
import json
import re
import requests
import os
import sys

def get_imageurl():
    query = sys.argv[1]
    print(query)
    id = ID
    api_key = API_KEY
    page_to = 6

    from_url = 'https://www.googleapis.com/customsearch/v1?'
    params = {
        'key': api_key,
        'q':query,
        'cx':id,
        'searchType':'image',
        'alt':'json',
        'lr' :'lang_ja',
    }

    start = 1
    f = open('imageURL.txt','w')

    for i in range(0, page_to):
        params['start'] = start
        req_url = from_url + urllib.urlencode(params)
        res = urllib.urlopen(req_url)
        dump = json.loads(res.read())
        for j in range(len(dump["items"])):
            f.write(dump["items"][j]["link"] + "\n")
        if not dump['queries'].has_key('nextPage'):
            break
        start = int(dump['queries']['nextPage'][0]['startIndex'])

    f.close()

def download_image(url, timeout = 10):
    response = requests.get(url, allow_redirects=False, timeout=timeout)
    if response.status_code != 200:
        e = Exception("HTTP status: " + response.status_code)
        raise e
    
    content_type = response.headers["content-type"]
    if 'image' not in content_type:
        e = Exception("Content-Type: " + content_type)
        raise e
    
    return response.content

def make_filename(base_dir, number, url):
    ext = ".png"
    filename = "%s%s"%(number, ext)
    
    fullpath = os.path.join(base_dir, filename)
    return fullpath

def save_image(filename, image):
    with open(filename, "wb") as fout:
        fout.write(image)

if __name__ == "__main__":
    get_imageurl()
    urls_txt = "imageURL.txt"
    query_dir = sys.argv[1]
    images_dir = "colorImageData/%s"%query_dir
    idx = 0
    abs_path = os.path.dirname(os.path.abspath(__file__))
    dir_path = "%s/%s"%(abs_path, images_dir)
    os.mkdir(dir_path)
    
    with open(urls_txt, "r") as fin:
        for line in fin:
            url = line.strip()
            filename = make_filename(dir_path, idx, url)
            
            print "%s" % (url)
            try:
                image = download_image(url)
                save_image(filename, image)
                idx += 1
            except KeyboardInterrupt:
                break
            except Exception as err:
                print "%s" % (err)

日頃Pythonを書かないので、見よう見まねで色々書いてみて、なんとか画像を取得できるようになった。

使い方はターミナルとかで、

python getImageData.py [query]

[query]の部分に検索したい画像のクエリを入れて実行する感じ。

取得するページ数を指定する変数がこれ。

page_to = [page]

今回は1クエリあたり50枚の画像を使いたい。 実行すると1ページあたり10枚の画像を取得してるっぽいけど、取得できない画像もあるので、多めに回しておいて、必要数を満たす戦法。

全体の動きとしては

1. APIを使って、[query]で画像検索をした結果をJSON形式で取得

2. JSONから画像のURL部分を抜き取って、imageURL.txtに書き込み

3. 書き込んだURLから画像を取得して、colorImageDataフォルダに保存

という感じ。

なんとも回りくどい感じになりましたが、まあ仕方ない。日頃Python書いてない人だから(言い訳) それに、ここまでは下準備ですから……。

では、このPythonのコードをProcessingで実行していきます。

ちなみに、"Processing Python" とかで検索すると、ProcessingのPython Modeについての記事がたくさん出てきて、そうじゃない……といった感じに。 また、Processingでは外部アプリケーションを実行できるlaunch()という命令があるようですが、これだと[query]を入力できないので、今回は使えそうにない……。

そこで今回は、ProcessBuilderというのを使っていきます。

import java.io.IOException;

void pythonExec() {
  try {
    ProcessBuilder builder = new ProcessBuilder("python", sketchPath()+"/python/getImageData.py", [query]);
    Process process = builder.start();
    
    int exitCode = process.waitFor();
    if (exitCode==0) {
      process.destroy();
    }
  } 
  catch (IOException e) {
    e.printStackTrace();
  }
  catch(InterruptedException ex) {
    ex.printStackTrace();
  }
}

はい、見ての通りjavaです。

このようにProcessBuilderを使うと、ターミナルでの入力形式に乗っ取って、Pythonを実行することができるようになり、[query]をパラメータとして設定できます。 あとはそのプロセスを実行して、waitFor()で終了判定を行い、プロセスを閉じるだけ。

この感じだと、他のターミナル上のコマンドも実行できそうで、いろいろ活用できそうですね!

眠れない夜に

寝苦しい夜に、ふと見かけた歯車を書く記事。

なんかいい感じにならないかなぁと思ったけれど、ならなかったという話。

Gear g;

void setup() {
  size(400, 400);
  g = new Gear(width/2.0, height/2.0, 150, 180);
}

void draw() {
  background(-1);
  g.display();
  g.update();
}

class Gear {
  float px, py, inR, outR, rotateR;
  Gear(float _px, float _py, float _inR, float _outR) {
    px = _px;
    py = _py;
    inR = _inR;
    outR = _outR;
    rotateR = 0;
  }

  void update() {
    rotateR++;
  }

  void display() {
    translate(px, py);
    rotate(radians(rotateR));
    stroke(50);
    strokeWeight(1);
    fill(50);
    ellipse(0, 0, inR*2, inR*2);
    float div=8;
    for (int i=0; i<div; i++) {
      beginShape();
      vertex(v(inR, 360*(i/div)-360/(div*4)).x, v(inR, 360*(i/div)-360/(div*4)).y);
      vertex(v(outR, 360*(i/div)-360/(div*6)).x, v(outR, 360*(i/div)-360/(div*6)).y);
      vertex(v(outR, 360*(i/div)+360/(div*6)).x, v(outR, 360*(i/div)+360/(div*6)).y);
      vertex(v(inR, 360*(i/div)+360/(div*4)).x, v(inR, 360*(i/div)+360/(div*4)).y);
      endShape();
    }
    fill(255);
    ellipse(0, 0, inR/3, inR/3);
  }

  PVector v(float _r, float _deg) {
    PVector pv = new PVector(_r*cos(radians(_deg)), _r*sin(radians(_deg)));
    return  pv;
  }
}